2001-09-25 22:53:13 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
2004-04-18 14:21:17 +00:00
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
1999-02-12 17:18:58 +00:00
|
|
|
*
|
2004-04-18 14:21:17 +00:00
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
1999-02-12 17:18:58 +00:00
|
|
|
*
|
2001-09-25 22:53:13 +00:00
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
1999-02-12 17:18:58 +00:00
|
|
|
*
|
1999-11-06 03:43:54 +00:00
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
2004-04-18 14:21:17 +00:00
|
|
|
* The Initial Developer of the Original Code is
|
2001-09-25 22:53:13 +00:00
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
1999-11-06 03:43:54 +00:00
|
|
|
*
|
2001-09-25 22:53:13 +00:00
|
|
|
* Contributor(s):
|
2000-01-11 20:49:15 +00:00
|
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
2002-01-09 13:51:37 +00:00
|
|
|
* Daniel Glazman <glazman@netscape.com>
|
2005-11-14 23:55:24 +00:00
|
|
|
* Masayuki Nakano <masayuki@d-toybox.com>
|
2010-03-14 22:52:07 +00:00
|
|
|
* Mats Palmgren <matspal@gmail.com>
|
2001-09-25 22:53:13 +00:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
2004-04-18 14:21:17 +00:00
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
2001-09-25 22:53:13 +00:00
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
2004-04-18 14:21:17 +00:00
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
2001-09-25 22:53:13 +00:00
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
2004-04-18 14:21:17 +00:00
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
2001-09-25 22:53:13 +00:00
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
1999-02-12 17:18:58 +00:00
|
|
|
|
1999-10-21 05:36:21 +00:00
|
|
|
#include "pratom.h"
|
1999-02-12 17:18:58 +00:00
|
|
|
#include "nsIDOMDocument.h"
|
2003-06-30 18:55:06 +00:00
|
|
|
#include "nsIDOMHTMLElement.h"
|
2006-07-29 00:04:40 +00:00
|
|
|
#include "nsIDOMNSHTMLElement.h"
|
2010-07-22 16:22:44 +00:00
|
|
|
#include "nsIDOMEventTarget.h"
|
|
|
|
#include "nsIDOMNSEvent.h"
|
2007-05-14 09:11:38 +00:00
|
|
|
#include "nsPIDOMEventTarget.h"
|
2010-05-04 17:40:39 +00:00
|
|
|
#include "nsIMEStateManager.h"
|
|
|
|
#include "nsFocusManager.h"
|
2002-11-23 01:26:58 +00:00
|
|
|
#include "nsIPrefBranch.h"
|
|
|
|
#include "nsIPrefService.h"
|
2002-01-16 03:31:25 +00:00
|
|
|
#include "nsUnicharUtils.h"
|
2002-09-18 19:42:38 +00:00
|
|
|
#include "nsReadableUtils.h"
|
1999-08-09 01:37:50 +00:00
|
|
|
|
1999-02-12 17:18:58 +00:00
|
|
|
#include "nsIDOMText.h"
|
|
|
|
#include "nsIDOMElement.h"
|
|
|
|
#include "nsIDOMAttr.h"
|
|
|
|
#include "nsIDOMNode.h"
|
2002-11-22 03:30:59 +00:00
|
|
|
#include "nsIDOMDocumentFragment.h"
|
1999-04-21 18:53:55 +00:00
|
|
|
#include "nsIDOMNamedNodeMap.h"
|
1999-02-12 17:18:58 +00:00
|
|
|
#include "nsIDOMNodeList.h"
|
|
|
|
#include "nsIDOMRange.h"
|
2006-08-30 14:17:05 +00:00
|
|
|
#include "nsIDOMHTMLBRElement.h"
|
2010-06-17 05:30:42 +00:00
|
|
|
#include "nsIDOMEventTarget.h"
|
1999-02-12 17:18:58 +00:00
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsITransactionManager.h"
|
1999-09-29 20:08:15 +00:00
|
|
|
#include "nsIAbsorbingTransaction.h"
|
1999-02-12 17:18:58 +00:00
|
|
|
#include "nsIPresShell.h"
|
2000-09-14 11:45:01 +00:00
|
|
|
#include "nsISelection.h"
|
|
|
|
#include "nsISelectionPrivate.h"
|
2001-07-16 02:40:48 +00:00
|
|
|
#include "nsISelectionController.h"
|
1999-02-12 17:18:58 +00:00
|
|
|
#include "nsIEnumerator.h"
|
2010-05-03 13:23:36 +00:00
|
|
|
#include "nsEditProperty.h"
|
1999-02-12 17:18:58 +00:00
|
|
|
#include "nsIAtom.h"
|
2008-07-16 10:52:01 +00:00
|
|
|
#include "nsCaret.h"
|
1999-12-08 03:39:36 +00:00
|
|
|
#include "nsIWidget.h"
|
2001-01-28 20:13:07 +00:00
|
|
|
#include "nsIPlaintextEditor.h"
|
2010-06-10 01:16:58 +00:00
|
|
|
#include "nsIPrivateDOMEvent.h"
|
|
|
|
#include "nsGUIEvent.h"
|
1999-04-27 17:14:28 +00:00
|
|
|
|
2000-07-18 22:11:31 +00:00
|
|
|
#include "nsIFrame.h" // Needed by IME code
|
|
|
|
|
2010-05-11 20:41:47 +00:00
|
|
|
#include "nsCSSStyleSheet.h"
|
1999-06-21 07:49:03 +00:00
|
|
|
|
1999-03-10 19:48:13 +00:00
|
|
|
#include "nsIContent.h"
|
2004-11-24 22:48:45 +00:00
|
|
|
#include "nsServiceManagerUtils.h"
|
1999-02-12 17:18:58 +00:00
|
|
|
|
|
|
|
// transactions the editor knows how to build
|
|
|
|
#include "EditAggregateTxn.h"
|
1999-09-29 20:08:15 +00:00
|
|
|
#include "PlaceholderTxn.h"
|
1999-02-12 17:18:58 +00:00
|
|
|
#include "ChangeAttributeTxn.h"
|
|
|
|
#include "CreateElementTxn.h"
|
1999-02-24 17:24:37 +00:00
|
|
|
#include "InsertElementTxn.h"
|
1999-02-12 17:18:58 +00:00
|
|
|
#include "DeleteElementTxn.h"
|
|
|
|
#include "InsertTextTxn.h"
|
|
|
|
#include "DeleteTextTxn.h"
|
|
|
|
#include "DeleteRangeTxn.h"
|
|
|
|
#include "SplitElementTxn.h"
|
|
|
|
#include "JoinElementTxn.h"
|
1999-08-09 01:37:50 +00:00
|
|
|
#include "nsStyleSheetTxns.h"
|
1999-06-29 20:31:22 +00:00
|
|
|
#include "IMETextTxn.h"
|
2008-10-17 20:04:55 +00:00
|
|
|
#include "nsString.h"
|
2001-01-28 20:13:07 +00:00
|
|
|
|
2005-06-16 21:20:57 +00:00
|
|
|
#include "nsEditor.h"
|
1999-09-29 20:08:15 +00:00
|
|
|
#include "nsEditorUtils.h"
|
2010-03-06 04:01:28 +00:00
|
|
|
#include "nsEditorEventListener.h"
|
2001-12-18 01:29:49 +00:00
|
|
|
#include "nsISelectionDisplay.h"
|
2005-02-01 21:12:53 +00:00
|
|
|
#include "nsIInlineSpellChecker.h"
|
2004-06-25 12:26:02 +00:00
|
|
|
#include "nsINameSpaceManager.h"
|
2004-08-06 11:56:46 +00:00
|
|
|
#include "nsIHTMLDocument.h"
|
2005-06-16 13:10:58 +00:00
|
|
|
#include "nsIParserService.h"
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2010-01-11 01:45:45 +00:00
|
|
|
#include "nsITransferable.h"
|
2010-05-21 20:36:42 +00:00
|
|
|
#include "nsComputedDOMStyle.h"
|
2010-01-11 01:45:45 +00:00
|
|
|
|
2010-05-19 23:22:19 +00:00
|
|
|
#include "mozilla/FunctionTimer.h"
|
|
|
|
|
1999-03-10 19:48:13 +00:00
|
|
|
#define NS_ERROR_EDITOR_NO_SELECTION NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_EDITOR,1)
|
1999-03-16 16:38:09 +00:00
|
|
|
#define NS_ERROR_EDITOR_NO_TEXTNODE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_EDITOR,2)
|
|
|
|
|
2000-10-28 22:17:53 +00:00
|
|
|
#ifdef NS_DEBUG_EDITOR
|
|
|
|
static PRBool gNoisy = PR_FALSE;
|
|
|
|
#endif
|
As a reminder, we decided to do this based strictly content. Some support for style-based text properties is written, but not used
anywhere any more.
* Cleaned up split and join undo/redo.
* Added TypeInState, a data struct that remembers things about text properties for collapsed selections, so you can type
* Ctrl-B with an insertion point and the next character will be bold.
* Added all the logic to handle inline vs. block elements when setting text properties.
* Added some support for italic and underline as well. Adding these things is pretty easy now. Ctrl-B, Ctrl-I, Ctrl-U for testing bold, italic, underline.
* Added all the logic to make sure we only add style tags where they're needed, so you should never get the same style tag nested within itself, except as needed for block elements.
* Added methods for testing a node to see if a particular style is set. This isn't 100% done yet, but with very little work we could have toolbar buttons that respond to selection changed notification that show the state of bold, italic, underline, etc. in real time. Supports tri-state: whole selection is bold, some of selection is bold, none of selection is bold, ...
* Fully undoable and redoable.
* Added some debug printfs to transactions and editors. all controlled by a gNoisy static in each module. helps me track down undo/redo problems. if the output bugs people enough, I'll shut it off and re-enable it in my local tree.
Noticably missing: make un-bold, make un-italic, etc. This is coming soon.
1999-04-01 17:58:07 +00:00
|
|
|
|
2010-06-17 05:29:40 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
#include "nsIDOMHTMLDocument.h"
|
|
|
|
#endif
|
|
|
|
|
1999-02-12 17:18:58 +00:00
|
|
|
|
2005-06-16 22:57:46 +00:00
|
|
|
// Defined in nsEditorRegistration.cpp
|
|
|
|
extern nsIParserService *sParserService;
|
2005-06-16 13:10:58 +00:00
|
|
|
|
2000-03-24 00:26:47 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// nsEditor: base editor class implementation
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2000-01-31 10:30:12 +00:00
|
|
|
|
1999-02-12 17:18:58 +00:00
|
|
|
nsEditor::nsEditor()
|
2004-02-19 02:44:03 +00:00
|
|
|
: mModCount(0)
|
2002-01-07 15:52:54 +00:00
|
|
|
, mPresShellWeak(nsnull)
|
1999-05-28 00:20:41 +00:00
|
|
|
, mUpdateCount(0)
|
2006-07-29 00:04:40 +00:00
|
|
|
, mSpellcheckCheckboxState(eTriUnset)
|
1999-09-29 20:08:15 +00:00
|
|
|
, mPlaceHolderTxn(nsnull)
|
|
|
|
, mPlaceHolderName(nsnull)
|
|
|
|
, mPlaceHolderBatch(0)
|
2000-01-31 10:30:12 +00:00
|
|
|
, mSelState(nsnull)
|
2000-08-26 04:03:50 +00:00
|
|
|
, mSavedSel()
|
|
|
|
, mRangeUpdater()
|
2000-11-29 22:06:02 +00:00
|
|
|
, mAction(nsnull)
|
|
|
|
, mDirection(eNone)
|
1999-10-26 18:54:47 +00:00
|
|
|
, mIMETextNode(nsnull)
|
|
|
|
, mIMETextOffset(0)
|
|
|
|
, mIMEBufferLength(0)
|
2005-04-11 17:53:28 +00:00
|
|
|
, mInIMEMode(PR_FALSE)
|
2003-05-20 02:02:56 +00:00
|
|
|
, mIsIMEComposing(PR_FALSE)
|
2005-04-11 17:53:28 +00:00
|
|
|
, mShouldTxnSetSelection(PR_TRUE)
|
2006-07-21 01:15:57 +00:00
|
|
|
, mDidPreDestroy(PR_FALSE)
|
1999-10-08 14:39:20 +00:00
|
|
|
, mDocDirtyState(-1)
|
|
|
|
, mDocWeak(nsnull)
|
2002-12-17 23:38:04 +00:00
|
|
|
, mPhonetic(nsnull)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
|
|
|
//initialize member variables here
|
|
|
|
}
|
|
|
|
|
|
|
|
nsEditor::~nsEditor()
|
|
|
|
{
|
2010-04-12 06:13:17 +00:00
|
|
|
NS_ASSERTION(!mDocWeak || mDidPreDestroy, "Why PreDestroy hasn't been called?");
|
|
|
|
|
2008-03-13 18:54:01 +00:00
|
|
|
mTxnMgr = nsnull;
|
2001-04-05 23:48:01 +00:00
|
|
|
|
2002-12-17 23:38:04 +00:00
|
|
|
delete mPhonetic;
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
|
2009-05-09 04:59:25 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsEditor)
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsEditor)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRootElement)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mInlineSpellChecker)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTxnMgr)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mIMETextRangeList)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mIMETextNode)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mActionListeners)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mEditorObservers)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mDocStateListeners)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mEventTarget)
|
2010-03-06 04:01:28 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mEventListener)
|
2009-05-09 04:59:25 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsEditor)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRootElement)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mInlineSpellChecker)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTxnMgr)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mIMETextRangeList)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mIMETextNode)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mActionListeners)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mEditorObservers)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mDocStateListeners)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEventTarget)
|
2010-03-06 04:01:28 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEventListener)
|
2009-05-09 04:59:25 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsEditor)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIPhonetic)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIEditorIMESupport)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIEditor)
|
|
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditor)
|
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsEditor, nsIEditor)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsEditor, nsIEditor)
|
1999-03-02 07:52:41 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
2000-03-24 00:26:47 +00:00
|
|
|
#pragma mark nsIEditorMethods
|
1999-08-09 01:37:50 +00:00
|
|
|
#pragma mark -
|
|
|
|
#endif
|
1999-03-02 05:30:53 +00:00
|
|
|
|
2000-04-28 06:20:36 +00:00
|
|
|
|
1999-03-02 05:30:53 +00:00
|
|
|
NS_IMETHODIMP
|
2000-05-04 08:33:48 +00:00
|
|
|
nsEditor::Init(nsIDOMDocument *aDoc, nsIPresShell* aPresShell, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(nsnull!=aDoc && nsnull!=aPresShell, "bad arg");
|
|
|
|
if ((nsnull==aDoc) || (nsnull==aPresShell))
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
2010-05-04 17:40:39 +00:00
|
|
|
// First only set flags, but other stuff shouldn't be initialized now.
|
|
|
|
// Don't move this call after initializing mDocWeak and mPresShellWeak.
|
|
|
|
// SetFlags() can check whether it's called during initialization or not by
|
|
|
|
// them. Note that SetFlags() will be called by PostCreate().
|
|
|
|
nsresult rv = SetFlags(aFlags);
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "SetFlags() failed");
|
|
|
|
|
2003-07-25 19:06:59 +00:00
|
|
|
mDocWeak = do_GetWeakReference(aDoc); // weak reference to doc
|
|
|
|
mPresShellWeak = do_GetWeakReference(aPresShell); // weak reference to pres shell
|
|
|
|
mSelConWeak = do_GetWeakReference(aSelCon); // weak reference to selectioncontroller
|
2010-04-12 02:35:18 +00:00
|
|
|
|
1999-08-25 10:51:55 +00:00
|
|
|
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
1999-06-21 07:49:03 +00:00
|
|
|
|
2005-03-24 19:00:01 +00:00
|
|
|
//set up root element if we are passed one.
|
2000-05-04 08:33:48 +00:00
|
|
|
if (aRoot)
|
2005-03-24 19:00:01 +00:00
|
|
|
mRootElement = do_QueryInterface(aRoot);
|
1999-06-12 21:15:14 +00:00
|
|
|
|
1999-02-12 17:18:58 +00:00
|
|
|
mUpdateCount=0;
|
|
|
|
|
2006-02-23 09:36:43 +00:00
|
|
|
/* initialize IME stuff */
|
2006-06-08 12:47:24 +00:00
|
|
|
mIMETextNode = nsnull;
|
1999-06-29 20:31:22 +00:00
|
|
|
mIMETextOffset = 0;
|
|
|
|
mIMEBufferLength = 0;
|
|
|
|
|
1999-02-13 04:48:09 +00:00
|
|
|
/* Show the caret */
|
2000-05-11 04:22:32 +00:00
|
|
|
aSelCon->SetCaretReadOnly(PR_FALSE);
|
|
|
|
aSelCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
|
2000-06-23 04:00:45 +00:00
|
|
|
|
2001-12-18 01:29:49 +00:00
|
|
|
aSelCon->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL);//we want to see all the selection reflected to user
|
1999-08-19 13:30:48 +00:00
|
|
|
|
2003-06-27 14:19:40 +00:00
|
|
|
#if 1
|
|
|
|
// THIS BLOCK CAUSES ASSERTIONS because sometimes we don't yet have
|
|
|
|
// a moz-br but we do have a presshell.
|
|
|
|
|
1999-06-22 21:42:44 +00:00
|
|
|
// Set the selection to the beginning:
|
2000-05-15 05:18:45 +00:00
|
|
|
|
|
|
|
//hack to get around this for now.
|
|
|
|
nsCOMPtr<nsIPresShell> shell = do_QueryReferent(mSelConWeak);
|
|
|
|
if (shell)
|
|
|
|
BeginningOfDocument();
|
2003-06-27 14:19:40 +00:00
|
|
|
#endif
|
1999-06-16 21:02:25 +00:00
|
|
|
|
1999-08-25 10:51:55 +00:00
|
|
|
NS_POSTCONDITION(mDocWeak && mPresShellWeak, "bad state");
|
1999-08-03 06:53:45 +00:00
|
|
|
|
2010-04-21 20:17:41 +00:00
|
|
|
// Make sure that the editor will be destroyed properly
|
|
|
|
mDidPreDestroy = PR_FALSE;
|
|
|
|
|
1999-08-03 06:53:45 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::PostCreate()
|
|
|
|
{
|
2010-05-04 17:40:39 +00:00
|
|
|
// Synchronize some stuff for the flags
|
|
|
|
nsresult rv = SetFlags(mFlags);
|
2006-07-29 00:04:40 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Set up listeners
|
|
|
|
rv = CreateEventListeners();
|
2005-03-24 19:00:01 +00:00
|
|
|
if (NS_FAILED(rv))
|
|
|
|
{
|
|
|
|
RemoveEventListeners();
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = InstallEventListeners();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
1999-12-21 15:27:54 +00:00
|
|
|
// nuke the modification count, so the doc appears unmodified
|
|
|
|
// do this before we notify listeners
|
2001-12-10 15:23:11 +00:00
|
|
|
ResetModificationCount();
|
1999-12-21 15:27:54 +00:00
|
|
|
|
1999-07-28 02:55:40 +00:00
|
|
|
// update the UI with our state
|
1999-08-03 00:58:38 +00:00
|
|
|
NotifyDocumentListeners(eDocumentCreated);
|
|
|
|
NotifyDocumentListeners(eDocumentStateChanged);
|
1999-07-28 02:55:40 +00:00
|
|
|
|
1999-02-12 17:18:58 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-03-06 04:01:28 +00:00
|
|
|
nsresult
|
|
|
|
nsEditor::CreateEventListeners()
|
|
|
|
{
|
2010-04-21 20:17:41 +00:00
|
|
|
// Don't create the handler twice
|
|
|
|
if (mEventListener)
|
|
|
|
return NS_OK;
|
2010-03-06 04:01:28 +00:00
|
|
|
mEventListener = do_QueryInterface(
|
2010-04-19 12:20:42 +00:00
|
|
|
static_cast<nsIDOMKeyListener*>(new nsEditorEventListener()));
|
2010-03-06 04:01:28 +00:00
|
|
|
NS_ENSURE_TRUE(mEventListener, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2005-03-24 19:00:01 +00:00
|
|
|
nsresult
|
|
|
|
nsEditor::InstallEventListeners()
|
|
|
|
{
|
2010-03-06 04:01:28 +00:00
|
|
|
NS_ENSURE_TRUE(mDocWeak && mPresShellWeak && mEventListener,
|
2005-03-24 19:00:01 +00:00
|
|
|
NS_ERROR_NOT_INITIALIZED);
|
2010-06-17 05:30:10 +00:00
|
|
|
|
|
|
|
// Initialize the event target.
|
|
|
|
nsCOMPtr<nsIContent> rootContent = do_QueryInterface(GetRoot());
|
|
|
|
NS_ENSURE_TRUE(rootContent, NS_ERROR_NOT_AVAILABLE);
|
|
|
|
mEventTarget = do_QueryInterface(rootContent->GetParent());
|
|
|
|
NS_ENSURE_TRUE(mEventTarget, NS_ERROR_NOT_AVAILABLE);
|
|
|
|
|
2010-04-19 12:20:42 +00:00
|
|
|
nsEditorEventListener* listener =
|
|
|
|
reinterpret_cast<nsEditorEventListener*>(mEventListener.get());
|
|
|
|
return listener->Connect(this);
|
2005-03-24 19:00:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsEditor::RemoveEventListeners()
|
|
|
|
{
|
2010-04-19 12:20:42 +00:00
|
|
|
if (!mDocWeak || !mEventListener) {
|
2006-06-17 00:17:26 +00:00
|
|
|
return;
|
|
|
|
}
|
2010-04-19 12:20:42 +00:00
|
|
|
reinterpret_cast<nsEditorEventListener*>(mEventListener.get())->Disconnect();
|
2010-06-17 05:30:10 +00:00
|
|
|
mEventTarget = nsnull;
|
2005-03-24 19:00:01 +00:00
|
|
|
}
|
2000-10-10 01:45:46 +00:00
|
|
|
|
2006-07-29 00:04:40 +00:00
|
|
|
PRBool
|
|
|
|
nsEditor::GetDesiredSpellCheckState()
|
|
|
|
{
|
|
|
|
// Check user override on this element
|
|
|
|
if (mSpellcheckCheckboxState != eTriUnset) {
|
|
|
|
return (mSpellcheckCheckboxState == eTriTrue);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check user preferences
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIPrefBranch> prefBranch =
|
|
|
|
do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
|
|
|
|
PRInt32 spellcheckLevel = 1;
|
|
|
|
if (NS_SUCCEEDED(rv) && prefBranch) {
|
|
|
|
prefBranch->GetIntPref("layout.spellcheckDefault", &spellcheckLevel);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spellcheckLevel == 0) {
|
|
|
|
return PR_FALSE; // Spellchecking forced off globally
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for password/readonly/disabled, which are not spellchecked
|
|
|
|
// regardless of DOM
|
2010-04-12 02:35:18 +00:00
|
|
|
if (IsPasswordEditor() || IsReadonly() || IsDisabled()) {
|
2006-07-29 00:04:40 +00:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
2006-11-15 06:39:25 +00:00
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
|
|
rv = GetPresShell(getter_AddRefs(presShell));
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
nsPresContext* context = presShell->GetPresContext();
|
|
|
|
if (context && !context->IsDynamic()) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-29 00:04:40 +00:00
|
|
|
// Check DOM state
|
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(GetRoot());
|
|
|
|
if (!content) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
2008-07-23 04:50:20 +00:00
|
|
|
if (content->IsRootOfNativeAnonymousSubtree()) {
|
2006-07-29 00:04:40 +00:00
|
|
|
content = content->GetParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNSHTMLElement> element = do_QueryInterface(content);
|
|
|
|
if (!element) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool enable;
|
|
|
|
element->GetSpellcheck(&enable);
|
|
|
|
|
|
|
|
return enable;
|
|
|
|
}
|
|
|
|
|
2000-10-10 01:45:46 +00:00
|
|
|
NS_IMETHODIMP
|
2008-12-12 08:34:43 +00:00
|
|
|
nsEditor::PreDestroy(PRBool aDestroyingFrames)
|
2000-10-10 01:45:46 +00:00
|
|
|
{
|
2006-07-29 00:04:40 +00:00
|
|
|
if (mDidPreDestroy)
|
|
|
|
return NS_OK;
|
2006-07-21 01:15:57 +00:00
|
|
|
|
2006-08-07 18:10:28 +00:00
|
|
|
// Let spellchecker clean up its observers etc. It is important not to
|
|
|
|
// actually free the spellchecker here, since the spellchecker could have
|
|
|
|
// caused flush notifications, which could have gotten here if a textbox
|
|
|
|
// is being removed. Setting the spellchecker to NULL could free the
|
|
|
|
// object that is still in use! It will be freed when the editor is
|
|
|
|
// destroyed.
|
|
|
|
if (mInlineSpellChecker)
|
2008-12-12 08:34:43 +00:00
|
|
|
mInlineSpellChecker->Cleanup(aDestroyingFrames);
|
2005-03-24 19:00:01 +00:00
|
|
|
|
2006-07-29 00:04:40 +00:00
|
|
|
// tell our listeners that the doc is going away
|
|
|
|
NotifyDocumentListeners(eDocumentToBeDestroyed);
|
2006-07-21 01:15:57 +00:00
|
|
|
|
2006-07-29 00:04:40 +00:00
|
|
|
// Unregister event listeners
|
|
|
|
RemoveEventListeners();
|
2006-10-09 15:41:26 +00:00
|
|
|
mActionListeners.Clear();
|
|
|
|
mEditorObservers.Clear();
|
|
|
|
mDocStateListeners.Clear();
|
|
|
|
mInlineSpellChecker = nsnull;
|
2005-03-24 19:00:01 +00:00
|
|
|
|
2006-07-29 00:04:40 +00:00
|
|
|
mDidPreDestroy = PR_TRUE;
|
2000-10-10 01:45:46 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-03-13 02:48:17 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::GetFlags(PRUint32 *aFlags)
|
|
|
|
{
|
|
|
|
*aFlags = mFlags;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::SetFlags(PRUint32 aFlags)
|
|
|
|
{
|
|
|
|
mFlags = aFlags;
|
2006-07-29 00:04:40 +00:00
|
|
|
|
2010-05-04 17:40:39 +00:00
|
|
|
if (!mDocWeak || !mPresShellWeak) {
|
|
|
|
// If we're initializing, we shouldn't do anything now.
|
|
|
|
// SetFlags() will be called by PostCreate(),
|
|
|
|
// we should synchronize some stuff for the flags at that time.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2006-07-29 00:04:40 +00:00
|
|
|
// Changing the flags can change whether spellchecking is on, so re-sync it
|
2010-05-04 17:40:39 +00:00
|
|
|
nsresult rv = SyncRealTimeSpell();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Might be changing editable state, so, we need to reset current IME state
|
2010-05-27 02:04:14 +00:00
|
|
|
// if we're focused and the flag change causes IME state change.
|
2010-05-04 17:40:39 +00:00
|
|
|
if (HasFocus()) {
|
|
|
|
// Use "enable" for the default value because if IME is disabled
|
|
|
|
// unexpectedly, it makes serious a11y problem.
|
|
|
|
PRUint32 newState = nsIContent::IME_STATUS_ENABLE;
|
|
|
|
rv = GetPreferredIMEState(&newState);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2010-05-27 02:04:14 +00:00
|
|
|
// NOTE: When the enabled state isn't going to be modified, this method
|
|
|
|
// is going to do nothing.
|
|
|
|
nsIMEStateManager::UpdateIMEState(newState);
|
2010-05-04 17:40:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-03-13 02:48:17 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2002-09-18 19:42:38 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::GetIsDocumentEditable(PRBool *aIsDocumentEditable)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aIsDocumentEditable);
|
|
|
|
nsCOMPtr<nsIDOMDocument> doc;
|
|
|
|
GetDocument(getter_AddRefs(doc));
|
|
|
|
*aIsDocumentEditable = doc ? PR_TRUE : PR_FALSE;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::GetDocument(nsIDOMDocument **aDoc)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aDoc, NS_ERROR_NULL_POINTER);
|
1999-08-09 01:37:50 +00:00
|
|
|
*aDoc = nsnull; // init out param
|
1999-08-25 10:51:55 +00:00
|
|
|
NS_PRECONDITION(mDocWeak, "bad state, mDocWeak weak pointer not initialized");
|
|
|
|
nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(mDocWeak);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
|
2000-04-28 06:20:36 +00:00
|
|
|
NS_ADDREF(*aDoc = doc);
|
|
|
|
return NS_OK;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
1999-02-12 17:18:58 +00:00
|
|
|
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
nsresult
|
|
|
|
nsEditor::GetPresShell(nsIPresShell **aPS)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aPS, NS_ERROR_NULL_POINTER);
|
1999-08-09 01:37:50 +00:00
|
|
|
*aPS = nsnull; // init out param
|
1999-08-25 10:51:55 +00:00
|
|
|
NS_PRECONDITION(mPresShellWeak, "bad state, null mPresShellWeak");
|
|
|
|
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
2000-04-27 07:37:12 +00:00
|
|
|
NS_ADDREF(*aPS = ps);
|
|
|
|
return NS_OK;
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2002-09-18 19:42:38 +00:00
|
|
|
/* attribute string contentsMIMEType; */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::GetContentsMIMEType(char * *aContentsMIMEType)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aContentsMIMEType);
|
|
|
|
*aContentsMIMEType = ToNewCString(mContentMIMEType);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::SetContentsMIMEType(const char * aContentsMIMEType)
|
|
|
|
{
|
|
|
|
mContentMIMEType.Assign(aContentsMIMEType ? aContentsMIMEType : "");
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-04-27 07:37:12 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::GetSelectionController(nsISelectionController **aSel)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aSel, NS_ERROR_NULL_POINTER);
|
2000-04-27 07:37:12 +00:00
|
|
|
*aSel = nsnull; // init out param
|
2000-04-28 06:20:36 +00:00
|
|
|
NS_PRECONDITION(mSelConWeak, "bad state, null mSelConWeak");
|
|
|
|
nsCOMPtr<nsISelectionController> selCon = do_QueryReferent(mSelConWeak);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
|
2000-04-27 07:37:12 +00:00
|
|
|
NS_ADDREF(*aSel = selCon);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-03-13 02:48:17 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::DeleteSelection(EDirection aAction)
|
|
|
|
{
|
|
|
|
return DeleteSelectionImpl(aAction);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-04-27 07:37:12 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_IMETHODIMP
|
2000-09-14 11:45:01 +00:00
|
|
|
nsEditor::GetSelection(nsISelection **aSelection)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
|
1999-08-09 01:37:50 +00:00
|
|
|
*aSelection = nsnull;
|
2000-04-28 06:20:36 +00:00
|
|
|
nsCOMPtr<nsISelectionController> selcon = do_QueryReferent(mSelConWeak);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(selcon, NS_ERROR_NOT_INITIALIZED);
|
2003-06-30 17:28:52 +00:00
|
|
|
return selcon->GetSelection(nsISelectionController::SELECTION_NORMAL, aSelection); // does an addref
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
|
1999-03-02 05:30:53 +00:00
|
|
|
NS_IMETHODIMP
|
2003-04-04 20:50:25 +00:00
|
|
|
nsEditor::DoTransaction(nsITransaction *aTxn)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
2003-05-23 21:43:10 +00:00
|
|
|
#ifdef NS_DEBUG_EDITOR
|
2003-04-04 20:50:25 +00:00
|
|
|
if (gNoisy) { printf("Editor::DoTransaction ----------\n"); }
|
2003-05-23 21:43:10 +00:00
|
|
|
#endif
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
nsresult result = NS_OK;
|
1999-09-29 20:08:15 +00:00
|
|
|
|
|
|
|
if (mPlaceHolderBatch && !mPlaceHolderTxn)
|
|
|
|
{
|
|
|
|
// it's pretty darn amazing how many different types of pointers
|
1999-11-01 15:15:35 +00:00
|
|
|
// this transaction goes through here. I bet this is a record.
|
|
|
|
|
|
|
|
// We start off with an EditTxn since that's what the factory returns.
|
2009-04-24 22:45:34 +00:00
|
|
|
nsRefPtr<EditTxn> editTxn = new PlaceholderTxn();
|
|
|
|
if (!editTxn) { return NS_ERROR_OUT_OF_MEMORY; }
|
1999-11-01 15:15:35 +00:00
|
|
|
|
|
|
|
// Then we QI to an nsIAbsorbingTransaction to get at placeholder functionality
|
|
|
|
nsCOMPtr<nsIAbsorbingTransaction> plcTxn;
|
2000-01-11 20:49:15 +00:00
|
|
|
editTxn->QueryInterface(NS_GET_IID(nsIAbsorbingTransaction), getter_AddRefs(plcTxn));
|
1999-11-01 15:15:35 +00:00
|
|
|
// have to use line above instead of "plcTxn = do_QueryInterface(editTxn);"
|
|
|
|
// due to our broken interface model for transactions.
|
|
|
|
|
1999-09-29 20:08:15 +00:00
|
|
|
// save off weak reference to placeholder txn
|
2003-07-25 19:06:59 +00:00
|
|
|
mPlaceHolderTxn = do_GetWeakReference(plcTxn);
|
2000-06-30 04:58:34 +00:00
|
|
|
plcTxn->Init(mPlaceHolderName, mSelState, this);
|
2000-01-31 10:30:12 +00:00
|
|
|
mSelState = nsnull; // placeholder txn took ownership of this pointer
|
|
|
|
|
2003-04-04 20:50:25 +00:00
|
|
|
// finally we QI to an nsITransaction since that's what DoTransaction() expects
|
1999-09-29 20:08:15 +00:00
|
|
|
nsCOMPtr<nsITransaction> theTxn = do_QueryInterface(plcTxn);
|
2003-04-04 20:50:25 +00:00
|
|
|
DoTransaction(theTxn); // we will recurse, but will not hit this case in the nested call
|
2002-10-08 23:06:38 +00:00
|
|
|
|
|
|
|
if (mTxnMgr)
|
|
|
|
{
|
2002-10-14 23:48:05 +00:00
|
|
|
nsCOMPtr<nsITransaction> topTxn;
|
|
|
|
result = mTxnMgr->PeekUndoStack(getter_AddRefs(topTxn));
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2002-10-08 23:06:38 +00:00
|
|
|
if (topTxn)
|
|
|
|
{
|
2002-10-14 23:48:05 +00:00
|
|
|
plcTxn = do_QueryInterface(topTxn);
|
2002-10-08 23:06:38 +00:00
|
|
|
if (plcTxn)
|
|
|
|
{
|
|
|
|
// there is a palceholder transaction on top of the undo stack. It is
|
|
|
|
// either the one we just created, or an earlier one that we are now merging
|
|
|
|
// into. From here on out remember this placeholder instead of the one
|
|
|
|
// we just created.
|
2003-07-25 19:06:59 +00:00
|
|
|
mPlaceHolderTxn = do_GetWeakReference(plcTxn);
|
2002-10-08 23:06:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-09-29 20:08:15 +00:00
|
|
|
}
|
1999-10-06 20:27:41 +00:00
|
|
|
|
|
|
|
if (aTxn)
|
|
|
|
{
|
2003-04-04 20:50:25 +00:00
|
|
|
// XXX: Why are we doing selection specific batching stuff here?
|
|
|
|
// XXX: Most entry points into the editor have auto variables that
|
|
|
|
// XXX: should trigger Begin/EndUpdateViewBatch() calls that will make
|
|
|
|
// XXX: these selection batch calls no-ops.
|
|
|
|
// XXX:
|
|
|
|
// XXX: I suspect that this was placed here to avoid multiple
|
|
|
|
// XXX: selection changed notifications from happening until after
|
|
|
|
// XXX: the transaction was done. I suppose that can still happen
|
|
|
|
// XXX: if an embedding application called DoTransaction() directly
|
|
|
|
// XXX: to pump its own transactions through the system, but in that
|
|
|
|
// XXX: case, wouldn't we want to use Begin/EndUpdateViewBatch() or
|
|
|
|
// XXX: its auto equivalent nsAutoUpdateViewBatch to ensure that
|
|
|
|
// XXX: selection listeners have access to accurate frame data?
|
|
|
|
// XXX:
|
|
|
|
// XXX: Note that if we did add Begin/EndUpdateViewBatch() calls
|
|
|
|
// XXX: we will need to make sure that they are disabled during
|
|
|
|
// XXX: the init of the editor for text widgets to avoid layout
|
|
|
|
// XXX: re-entry during initial reflow. - kin
|
|
|
|
|
1999-10-06 20:27:41 +00:00
|
|
|
// get the selection and start a batch change
|
2000-09-14 11:45:01 +00:00
|
|
|
nsCOMPtr<nsISelection>selection;
|
1999-10-06 20:27:41 +00:00
|
|
|
result = GetSelection(getter_AddRefs(selection));
|
2010-06-21 15:02:14 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
|
|
|
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
|
2000-09-14 11:45:01 +00:00
|
|
|
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(selection));
|
1999-10-06 20:27:41 +00:00
|
|
|
|
2000-09-14 11:45:01 +00:00
|
|
|
selPrivate->StartBatchChanges();
|
2003-04-04 20:50:25 +00:00
|
|
|
|
1999-10-06 20:27:41 +00:00
|
|
|
if (mTxnMgr) {
|
2001-03-09 14:23:59 +00:00
|
|
|
result = mTxnMgr->DoTransaction(aTxn);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
1999-10-06 20:27:41 +00:00
|
|
|
else {
|
2001-03-09 14:23:59 +00:00
|
|
|
result = aTxn->DoTransaction();
|
1999-10-06 20:27:41 +00:00
|
|
|
}
|
|
|
|
if (NS_SUCCEEDED(result)) {
|
|
|
|
result = DoAfterDoTransaction(aTxn);
|
|
|
|
}
|
2003-04-04 20:50:25 +00:00
|
|
|
|
2000-09-14 11:45:01 +00:00
|
|
|
selPrivate->EndBatchChanges(); // no need to check result here, don't lose result of operation
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
1999-11-01 15:15:35 +00:00
|
|
|
|
2007-03-10 15:50:14 +00:00
|
|
|
NS_POSTCONDITION((NS_SUCCEEDED(result)), "transaction did not execute properly");
|
1999-10-06 20:27:41 +00:00
|
|
|
|
1999-02-12 17:18:58 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::EnableUndo(PRBool aEnable)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
nsresult result=NS_OK;
|
|
|
|
|
|
|
|
if (PR_TRUE==aEnable)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
if (!mTxnMgr)
|
|
|
|
{
|
2003-07-08 20:38:51 +00:00
|
|
|
mTxnMgr = do_CreateInstance(NS_TRANSACTIONMANAGER_CONTRACTID, &result);
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_FAILED(result) || !mTxnMgr) {
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mTxnMgr->SetMaxTransactionCount(-1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // disable the transaction manager if it is enabled
|
|
|
|
if (mTxnMgr)
|
|
|
|
{
|
|
|
|
mTxnMgr->Clear();
|
|
|
|
mTxnMgr->SetMaxTransactionCount(0);
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2003-07-08 20:38:51 +00:00
|
|
|
return NS_OK;
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2000-02-16 01:36:30 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::GetTransactionManager(nsITransactionManager* *aTxnManager)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aTxnManager);
|
|
|
|
|
|
|
|
*aTxnManager = NULL;
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(mTxnMgr, NS_ERROR_FAILURE);
|
2000-02-16 01:36:30 +00:00
|
|
|
|
|
|
|
NS_ADDREF(*aTxnManager = mTxnMgr);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-02-05 22:24:12 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::SetTransactionManager(nsITransactionManager *aTxnManager)
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(aTxnManager, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
mTxnMgr = aTxnManager;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-02-16 01:36:30 +00:00
|
|
|
|
1999-03-02 05:30:53 +00:00
|
|
|
NS_IMETHODIMP
|
1999-08-09 01:37:50 +00:00
|
|
|
nsEditor::Undo(PRUint32 aCount)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
2003-05-23 21:43:10 +00:00
|
|
|
#ifdef NS_DEBUG_EDITOR
|
2000-10-28 22:17:53 +00:00
|
|
|
if (gNoisy) { printf("Editor::Undo ----------\n"); }
|
2003-05-23 21:43:10 +00:00
|
|
|
#endif
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
nsresult result = NS_OK;
|
1999-12-09 22:35:17 +00:00
|
|
|
ForceCompositionEnd();
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2004-03-26 14:20:04 +00:00
|
|
|
PRBool hasTxnMgr, hasTransaction = PR_FALSE;
|
|
|
|
CanUndo(&hasTxnMgr, &hasTransaction);
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(hasTransaction, result);
|
2004-03-26 14:20:04 +00:00
|
|
|
|
1999-12-07 08:30:19 +00:00
|
|
|
nsAutoRules beginRulesSniffing(this, kOpUndo, nsIEditor::eNone);
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
if ((nsITransactionManager *)nsnull!=mTxnMgr.get())
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
PRUint32 i=0;
|
|
|
|
for ( ; i<aCount; i++)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
2001-03-09 14:23:59 +00:00
|
|
|
result = mTxnMgr->UndoTransaction();
|
1999-08-09 01:37:50 +00:00
|
|
|
|
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
result = DoAfterUndoTransaction();
|
1999-08-25 10:51:55 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_FAILED(result))
|
|
|
|
break;
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2000-07-16 06:36:27 +00:00
|
|
|
NotifyEditorObservers();
|
1999-02-12 17:18:58 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2001-04-07 00:45:26 +00:00
|
|
|
NS_IMETHODIMP nsEditor::CanUndo(PRBool *aIsEnabled, PRBool *aCanUndo)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aIsEnabled && aCanUndo, NS_ERROR_NULL_POINTER);
|
2001-04-07 00:45:26 +00:00
|
|
|
*aIsEnabled = ((PRBool)((nsITransactionManager *)0!=mTxnMgr.get()));
|
|
|
|
if (*aIsEnabled)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
|
|
|
PRInt32 numTxns=0;
|
|
|
|
mTxnMgr->GetNumberOfUndoItems(&numTxns);
|
2001-04-07 00:45:26 +00:00
|
|
|
*aCanUndo = ((PRBool)(0!=numTxns));
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
else {
|
2001-04-07 00:45:26 +00:00
|
|
|
*aCanUndo = PR_FALSE;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
|
1999-03-02 05:30:53 +00:00
|
|
|
NS_IMETHODIMP
|
1999-08-09 01:37:50 +00:00
|
|
|
nsEditor::Redo(PRUint32 aCount)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
2003-05-23 21:43:10 +00:00
|
|
|
#ifdef NS_DEBUG_EDITOR
|
2000-10-28 22:17:53 +00:00
|
|
|
if (gNoisy) { printf("Editor::Redo ----------\n"); }
|
2003-05-23 21:43:10 +00:00
|
|
|
#endif
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
nsresult result = NS_OK;
|
|
|
|
|
2004-03-26 14:20:04 +00:00
|
|
|
PRBool hasTxnMgr, hasTransaction = PR_FALSE;
|
|
|
|
CanRedo(&hasTxnMgr, &hasTransaction);
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(hasTransaction, result);
|
2004-03-26 14:20:04 +00:00
|
|
|
|
1999-12-07 08:30:19 +00:00
|
|
|
nsAutoRules beginRulesSniffing(this, kOpRedo, nsIEditor::eNone);
|
1999-08-09 01:37:50 +00:00
|
|
|
|
|
|
|
if ((nsITransactionManager *)nsnull!=mTxnMgr.get())
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
PRUint32 i=0;
|
|
|
|
for ( ; i<aCount; i++)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
2001-03-09 14:23:59 +00:00
|
|
|
result = mTxnMgr->RedoTransaction();
|
1999-08-09 01:37:50 +00:00
|
|
|
|
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
result = DoAfterRedoTransaction();
|
|
|
|
|
|
|
|
if (NS_FAILED(result))
|
|
|
|
break;
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2000-07-16 06:36:27 +00:00
|
|
|
NotifyEditorObservers();
|
1999-02-12 17:18:58 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2001-04-07 00:45:26 +00:00
|
|
|
NS_IMETHODIMP nsEditor::CanRedo(PRBool *aIsEnabled, PRBool *aCanRedo)
|
1999-04-21 18:53:55 +00:00
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aIsEnabled && aCanRedo, NS_ERROR_NULL_POINTER);
|
2001-04-07 00:45:26 +00:00
|
|
|
|
|
|
|
*aIsEnabled = ((PRBool)((nsITransactionManager *)0!=mTxnMgr.get()));
|
|
|
|
if (*aIsEnabled)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
|
|
|
PRInt32 numTxns=0;
|
|
|
|
mTxnMgr->GetNumberOfRedoItems(&numTxns);
|
2001-04-07 00:45:26 +00:00
|
|
|
*aCanRedo = ((PRBool)(0!=numTxns));
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
else {
|
2001-04-07 00:45:26 +00:00
|
|
|
*aCanRedo = PR_FALSE;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-04-21 18:53:55 +00:00
|
|
|
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::BeginTransaction()
|
|
|
|
{
|
|
|
|
BeginUpdateViewBatch();
|
1999-04-21 18:53:55 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
if ((nsITransactionManager *)nsnull!=mTxnMgr.get())
|
1999-04-21 18:53:55 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
mTxnMgr->BeginBatch();
|
1999-05-27 04:10:04 +00:00
|
|
|
}
|
1999-02-12 17:18:58 +00:00
|
|
|
|
1999-07-14 22:29:39 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-03-02 05:30:53 +00:00
|
|
|
NS_IMETHODIMP
|
1999-08-09 01:37:50 +00:00
|
|
|
nsEditor::EndTransaction()
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
1999-07-06 23:02:12 +00:00
|
|
|
if ((nsITransactionManager *)nsnull!=mTxnMgr.get())
|
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
mTxnMgr->EndBatch();
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
1999-05-12 22:24:47 +00:00
|
|
|
|
1999-07-06 23:02:12 +00:00
|
|
|
EndUpdateViewBatch();
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
return NS_OK;
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
|
1999-09-29 20:08:15 +00:00
|
|
|
|
|
|
|
// These two routines are similar to the above, but do not use
|
|
|
|
// the transaction managers batching feature. Instead we use
|
|
|
|
// a placeholder transaction to wrap up any further transaction
|
|
|
|
// while the batch is open. The advantage of this is that
|
|
|
|
// placeholder transactions can later merge, if needed. Merging
|
|
|
|
// is unavailable between transaction manager batches.
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::BeginPlaceHolderTransaction(nsIAtom *aName)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(mPlaceHolderBatch >= 0, "negative placeholder batch count!");
|
|
|
|
if (!mPlaceHolderBatch)
|
|
|
|
{
|
|
|
|
// time to turn on the batch
|
|
|
|
BeginUpdateViewBatch();
|
|
|
|
mPlaceHolderTxn = nsnull;
|
|
|
|
mPlaceHolderName = aName;
|
2000-09-14 11:45:01 +00:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
1999-09-29 20:08:15 +00:00
|
|
|
nsresult res = GetSelection(getter_AddRefs(selection));
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-01-31 10:30:12 +00:00
|
|
|
mSelState = new nsSelectionState();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(mSelState, NS_ERROR_OUT_OF_MEMORY);
|
2003-11-17 20:45:37 +00:00
|
|
|
|
2000-01-31 10:30:12 +00:00
|
|
|
mSelState->SaveSelection(selection);
|
1999-09-29 20:08:15 +00:00
|
|
|
}
|
|
|
|
mPlaceHolderBatch++;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::EndPlaceHolderTransaction()
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(mPlaceHolderBatch > 0, "zero or negative placeholder batch count when ending batch!");
|
|
|
|
if (mPlaceHolderBatch == 1)
|
|
|
|
{
|
2003-04-20 01:03:40 +00:00
|
|
|
nsCOMPtr<nsISelection>selection;
|
2009-01-06 19:25:58 +00:00
|
|
|
GetSelection(getter_AddRefs(selection));
|
2003-04-02 05:48:09 +00:00
|
|
|
|
2003-04-20 01:03:40 +00:00
|
|
|
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(selection));
|
|
|
|
|
|
|
|
// By making the assumption that no reflow happens during the calls
|
|
|
|
// to EndUpdateViewBatch and ScrollSelectionIntoView, we are able to
|
|
|
|
// allow the selection to cache a frame offset which is used by the
|
|
|
|
// caret drawing code. We only enable this cache here; at other times,
|
|
|
|
// we have no way to know whether reflow invalidates it
|
|
|
|
// See bugs 35296 and 199412.
|
|
|
|
if (selPrivate) {
|
|
|
|
selPrivate->SetCanCacheFrameOffset(PR_TRUE);
|
2003-04-02 05:48:09 +00:00
|
|
|
}
|
|
|
|
|
1999-09-29 20:08:15 +00:00
|
|
|
// time to turn off the batch
|
|
|
|
EndUpdateViewBatch();
|
2000-08-14 02:39:37 +00:00
|
|
|
// make sure selection is in view
|
2008-02-28 15:28:37 +00:00
|
|
|
|
|
|
|
// After ScrollSelectionIntoView(), the pending notifications might be
|
|
|
|
// flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
|
2002-06-13 20:35:12 +00:00
|
|
|
ScrollSelectionIntoView(PR_FALSE);
|
2000-08-14 02:39:37 +00:00
|
|
|
|
2003-04-20 01:03:40 +00:00
|
|
|
// cached for frame offset are Not available now
|
|
|
|
if (selPrivate) {
|
|
|
|
selPrivate->SetCanCacheFrameOffset(PR_FALSE);
|
2003-04-02 05:48:09 +00:00
|
|
|
}
|
|
|
|
|
2000-01-31 10:30:12 +00:00
|
|
|
if (mSelState)
|
|
|
|
{
|
|
|
|
// we saved the selection state, but never got to hand it to placeholder
|
|
|
|
// (else we ould have nulled out this pointer), so destroy it to prevent leaks.
|
|
|
|
delete mSelState;
|
|
|
|
mSelState = nsnull;
|
|
|
|
}
|
1999-09-29 20:08:15 +00:00
|
|
|
if (mPlaceHolderTxn) // we might have never made a placeholder if no action took place
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIAbsorbingTransaction> plcTxn = do_QueryReferent(mPlaceHolderTxn);
|
|
|
|
if (plcTxn)
|
|
|
|
{
|
|
|
|
plcTxn->EndPlaceHolderBatch();
|
|
|
|
}
|
1999-11-05 00:46:06 +00:00
|
|
|
else
|
1999-09-29 20:08:15 +00:00
|
|
|
{
|
1999-11-05 00:46:06 +00:00
|
|
|
// in the future we will check to make sure undo is off here,
|
|
|
|
// since that is the only known case where the placeholdertxn would disappear on us.
|
|
|
|
// For now just removing the assert.
|
1999-09-29 20:08:15 +00:00
|
|
|
}
|
2000-07-16 06:36:27 +00:00
|
|
|
// notify editor observers of action unless it is uncommitted IME
|
|
|
|
if (!mInIMEMode) NotifyEditorObservers();
|
1999-09-29 20:08:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
mPlaceHolderBatch--;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-04-12 03:41:06 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::ShouldTxnSetSelection(PRBool *aResult)
|
2000-01-04 03:09:41 +00:00
|
|
|
{
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
|
2000-01-04 03:09:41 +00:00
|
|
|
*aResult = mShouldTxnSetSelection;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-04-12 03:41:06 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::SetShouldTxnSetSelection(PRBool aShould)
|
|
|
|
{
|
|
|
|
mShouldTxnSetSelection = aShould;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-01-04 03:09:41 +00:00
|
|
|
|
2001-03-13 02:48:17 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::GetDocumentIsEmpty(PRBool *aDocumentIsEmpty)
|
|
|
|
{
|
2005-03-24 19:00:01 +00:00
|
|
|
*aDocumentIsEmpty = PR_TRUE;
|
|
|
|
|
|
|
|
nsIDOMElement *rootElement = GetRoot();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(rootElement, NS_ERROR_NULL_POINTER);
|
2005-03-24 19:00:01 +00:00
|
|
|
|
|
|
|
PRBool hasChildNodes;
|
|
|
|
nsresult res = rootElement->HasChildNodes(&hasChildNodes);
|
|
|
|
|
|
|
|
*aDocumentIsEmpty = !hasChildNodes;
|
2001-03-13 02:48:17 +00:00
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
// XXX: the rule system should tell us which node to select all on (ie, the root, or the body)
|
|
|
|
NS_IMETHODIMP nsEditor::SelectAll()
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
1999-08-25 10:51:55 +00:00
|
|
|
if (!mDocWeak || !mPresShellWeak) { return NS_ERROR_NOT_INITIALIZED; }
|
1999-12-09 22:35:17 +00:00
|
|
|
ForceCompositionEnd();
|
1999-07-06 23:02:12 +00:00
|
|
|
|
2000-05-08 04:01:26 +00:00
|
|
|
nsCOMPtr<nsISelectionController> selCon = do_QueryReferent(mSelConWeak);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
|
2003-06-30 17:28:52 +00:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
2000-05-08 04:01:26 +00:00
|
|
|
nsresult result = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_SUCCEEDED(result) && selection)
|
1999-07-06 23:02:12 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
result = SelectEntireDocument(selection);
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_IMETHODIMP nsEditor::BeginningOfDocument()
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
1999-08-25 10:51:55 +00:00
|
|
|
if (!mDocWeak || !mPresShellWeak) { return NS_ERROR_NOT_INITIALIZED; }
|
1999-06-10 19:41:40 +00:00
|
|
|
|
2002-10-08 22:53:55 +00:00
|
|
|
// get the selection
|
2000-09-14 11:45:01 +00:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
2002-10-08 22:53:55 +00:00
|
|
|
nsresult result = GetSelection(getter_AddRefs(selection));
|
2010-06-17 20:44:35 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
|
2002-10-08 22:53:55 +00:00
|
|
|
|
|
|
|
// get the root element
|
2005-03-24 19:00:01 +00:00
|
|
|
nsIDOMElement *rootElement = GetRoot();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(rootElement, NS_ERROR_NULL_POINTER);
|
2002-10-08 22:53:55 +00:00
|
|
|
|
|
|
|
// find first editable thingy
|
|
|
|
nsCOMPtr<nsIDOMNode> firstNode;
|
|
|
|
result = GetFirstEditableNode(rootElement, address_of(firstNode));
|
|
|
|
if (firstNode)
|
1999-05-17 13:31:56 +00:00
|
|
|
{
|
2002-10-08 22:53:55 +00:00
|
|
|
// if firstNode is text, set selection to beginning of the text node
|
|
|
|
if (IsTextNode(firstNode))
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
2002-10-08 22:53:55 +00:00
|
|
|
result = selection->Collapse(firstNode, 0);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
2002-10-08 22:53:55 +00:00
|
|
|
else
|
|
|
|
{ // otherwise, it's a leaf node and we set the selection just in front of it
|
|
|
|
nsCOMPtr<nsIDOMNode> parentNode;
|
|
|
|
result = firstNode->GetParentNode(getter_AddRefs(parentNode));
|
|
|
|
if (NS_FAILED(result)) { return result; }
|
|
|
|
if (!parentNode) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
PRInt32 offsetInParent;
|
|
|
|
result = nsEditor::GetChildOffset(firstNode, parentNode, offsetInParent);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2002-10-08 22:53:55 +00:00
|
|
|
result = selection->Collapse(parentNode, offsetInParent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-03-24 19:00:01 +00:00
|
|
|
// just the root node, set selection to inside the root
|
2002-10-08 22:53:55 +00:00
|
|
|
result = selection->Collapse(rootElement, 0);
|
1999-05-17 13:31:56 +00:00
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
return result;
|
1999-03-10 19:48:13 +00:00
|
|
|
}
|
|
|
|
|
2000-08-08 04:05:26 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::EndOfDocument()
|
|
|
|
{
|
|
|
|
if (!mDocWeak || !mPresShellWeak) { return NS_ERROR_NOT_INITIALIZED; }
|
|
|
|
nsresult res;
|
2005-03-24 19:00:01 +00:00
|
|
|
|
2000-08-08 04:05:26 +00:00
|
|
|
// get selection
|
2000-09-14 11:45:01 +00:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
2000-08-08 04:05:26 +00:00
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
|
2000-08-08 04:05:26 +00:00
|
|
|
|
|
|
|
// get the root element
|
2005-03-24 19:00:01 +00:00
|
|
|
nsIDOMElement *rootElement = GetRoot();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(rootElement, NS_ERROR_NULL_POINTER);
|
2005-03-24 19:00:01 +00:00
|
|
|
|
2000-08-08 04:05:26 +00:00
|
|
|
// get the length of the rot element
|
|
|
|
PRUint32 len;
|
2005-03-24 19:00:01 +00:00
|
|
|
res = GetLengthOfDOMNode(rootElement, len);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2005-03-24 19:00:01 +00:00
|
|
|
|
2000-08-08 04:05:26 +00:00
|
|
|
// set the selection to after the last child of the root element
|
2005-03-24 19:00:01 +00:00
|
|
|
return selection->Collapse(rootElement, (PRInt32)len);
|
2000-08-08 04:05:26 +00:00
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::GetDocumentModified(PRBool *outDocModified)
|
1999-03-10 21:29:41 +00:00
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(outDocModified, NS_ERROR_NULL_POINTER);
|
1999-05-14 19:24:10 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
PRInt32 modCount = 0;
|
2001-12-10 15:23:11 +00:00
|
|
|
GetModificationCount(&modCount);
|
1999-05-14 19:24:10 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
*outDocModified = (modCount != 0);
|
|
|
|
return NS_OK;
|
1999-03-10 21:29:41 +00:00
|
|
|
}
|
|
|
|
|
1999-08-13 22:26:50 +00:00
|
|
|
NS_IMETHODIMP
|
2003-06-17 16:40:34 +00:00
|
|
|
nsEditor::GetDocumentCharacterSet(nsACString &characterSet)
|
1999-08-13 22:26:50 +00:00
|
|
|
{
|
1999-08-20 23:52:36 +00:00
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
|
|
|
2003-06-30 17:28:52 +00:00
|
|
|
nsresult rv = GetPresShell(getter_AddRefs(presShell));
|
1999-08-20 23:52:36 +00:00
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
{
|
2004-08-02 04:52:55 +00:00
|
|
|
nsIDocument *doc = presShell->GetDocument();
|
2003-10-22 06:09:48 +00:00
|
|
|
if (doc) {
|
|
|
|
characterSet = doc->GetDocumentCharacterSet();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2001-04-07 00:45:26 +00:00
|
|
|
rv = NS_ERROR_NULL_POINTER;
|
1999-08-20 23:52:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
|
1999-08-13 22:26:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2003-06-17 16:40:34 +00:00
|
|
|
nsEditor::SetDocumentCharacterSet(const nsACString& characterSet)
|
1999-08-13 22:26:50 +00:00
|
|
|
{
|
1999-08-20 23:52:36 +00:00
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
2003-06-30 17:28:52 +00:00
|
|
|
nsresult rv = GetPresShell(getter_AddRefs(presShell));
|
1999-08-20 23:52:36 +00:00
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
{
|
2004-08-02 04:52:55 +00:00
|
|
|
nsIDocument *doc = presShell->GetDocument();
|
2000-04-26 01:00:50 +00:00
|
|
|
if (doc) {
|
2003-10-22 06:09:48 +00:00
|
|
|
doc->SetDocumentCharacterSet(characterSet);
|
|
|
|
return NS_OK;
|
2000-04-26 01:00:50 +00:00
|
|
|
}
|
2001-04-07 00:45:26 +00:00
|
|
|
rv = NS_ERROR_NULL_POINTER;
|
1999-08-20 23:52:36 +00:00
|
|
|
}
|
1999-08-13 22:26:50 +00:00
|
|
|
|
1999-08-20 23:52:36 +00:00
|
|
|
return rv;
|
1999-08-13 22:26:50 +00:00
|
|
|
}
|
|
|
|
|
2001-03-13 02:48:17 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::Cut()
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2001-04-07 00:45:26 +00:00
|
|
|
nsEditor::CanCut(PRBool *aCanCut)
|
2001-03-13 02:48:17 +00:00
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::Copy()
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2001-04-07 00:45:26 +00:00
|
|
|
nsEditor::CanCopy(PRBool *aCanCut)
|
2001-03-13 02:48:17 +00:00
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::Paste(PRInt32 aSelectionType)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2010-01-11 01:45:45 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::PasteTransferable(nsITransferable *aTransferable)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2001-03-13 02:48:17 +00:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 00:45:26 +00:00
|
|
|
nsEditor::CanPaste(PRInt32 aSelectionType, PRBool *aCanPaste)
|
2001-03-13 02:48:17 +00:00
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2010-01-11 01:45:45 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::CanPasteTransferable(nsITransferable *aTransferable, PRBool *aCanPaste)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2001-03-13 02:48:17 +00:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 00:45:26 +00:00
|
|
|
nsEditor::CanDrag(nsIDOMEvent *aEvent, PRBool *aCanDrag)
|
2001-03-13 02:48:17 +00:00
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::DoDrag(nsIDOMEvent *aEvent)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::InsertFromDrop(nsIDOMEvent *aEvent)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_IMETHODIMP
|
2002-03-23 22:16:54 +00:00
|
|
|
nsEditor::SetAttribute(nsIDOMElement *aElement, const nsAString & aAttribute, const nsAString & aValue)
|
1999-03-10 21:29:41 +00:00
|
|
|
{
|
2007-07-02 14:01:27 +00:00
|
|
|
nsRefPtr<ChangeAttributeTxn> txn;
|
|
|
|
nsresult result = CreateTxnForSetAttribute(aElement, aAttribute, aValue,
|
|
|
|
getter_AddRefs(txn));
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_SUCCEEDED(result)) {
|
2003-04-04 20:50:25 +00:00
|
|
|
result = DoTransaction(txn);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
1999-06-10 19:41:40 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::GetAttributeValue(nsIDOMElement *aElement,
|
2002-03-23 22:16:54 +00:00
|
|
|
const nsAString & aAttribute,
|
|
|
|
nsAString & aResultValue,
|
2001-04-07 00:45:26 +00:00
|
|
|
PRBool *aResultIsSet)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aResultIsSet, NS_ERROR_NULL_POINTER);
|
2001-04-07 00:45:26 +00:00
|
|
|
*aResultIsSet=PR_FALSE;
|
1999-08-09 01:37:50 +00:00
|
|
|
nsresult result=NS_OK;
|
2003-06-30 17:28:52 +00:00
|
|
|
if (aElement)
|
1999-07-19 19:37:08 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
nsCOMPtr<nsIDOMAttr> attNode;
|
|
|
|
result = aElement->GetAttributeNode(aAttribute, getter_AddRefs(attNode));
|
|
|
|
if ((NS_SUCCEEDED(result)) && attNode)
|
1999-07-19 19:37:08 +00:00
|
|
|
{
|
2001-04-07 00:45:26 +00:00
|
|
|
attNode->GetSpecified(aResultIsSet);
|
1999-08-09 01:37:50 +00:00
|
|
|
attNode->GetValue(aResultValue);
|
1999-04-02 01:34:05 +00:00
|
|
|
}
|
1999-04-01 14:28:13 +00:00
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
return result;
|
1999-03-10 21:29:41 +00:00
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_IMETHODIMP
|
2002-03-23 22:16:54 +00:00
|
|
|
nsEditor::RemoveAttribute(nsIDOMElement *aElement, const nsAString& aAttribute)
|
1999-05-27 00:08:15 +00:00
|
|
|
{
|
2007-07-02 14:01:27 +00:00
|
|
|
nsRefPtr<ChangeAttributeTxn> txn;
|
|
|
|
nsresult result = CreateTxnForRemoveAttribute(aElement, aAttribute,
|
|
|
|
getter_AddRefs(txn));
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_SUCCEEDED(result)) {
|
2003-04-04 20:50:25 +00:00
|
|
|
result = DoTransaction(txn);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
return result;
|
1999-05-27 00:08:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-03-24 00:26:47 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::MarkNodeDirty(nsIDOMNode* aNode)
|
|
|
|
{
|
|
|
|
// mark the node dirty.
|
2010-05-03 13:23:36 +00:00
|
|
|
nsCOMPtr<nsIContent> element (do_QueryInterface(aNode));
|
2000-03-24 00:26:47 +00:00
|
|
|
if (element)
|
2010-05-03 13:23:36 +00:00
|
|
|
element->SetAttr(kNameSpaceID_None, nsEditProperty::mozdirty,
|
|
|
|
EmptyString(), PR_FALSE);
|
2000-03-24 00:26:47 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2005-12-05 18:07:33 +00:00
|
|
|
NS_IMETHODIMP nsEditor::GetInlineSpellChecker(PRBool autoCreate,
|
|
|
|
nsIInlineSpellChecker ** aInlineSpellChecker)
|
2005-02-01 21:12:53 +00:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aInlineSpellChecker);
|
2006-07-21 01:15:57 +00:00
|
|
|
|
|
|
|
if (mDidPreDestroy) {
|
|
|
|
// Don't allow people to get or create the spell checker once the editor
|
|
|
|
// is going away.
|
|
|
|
*aInlineSpellChecker = nsnull;
|
|
|
|
return autoCreate ? NS_ERROR_NOT_AVAILABLE : NS_OK;
|
|
|
|
}
|
2005-02-01 21:12:53 +00:00
|
|
|
|
2008-05-27 17:55:13 +00:00
|
|
|
nsresult rv;
|
2005-12-05 18:07:33 +00:00
|
|
|
if (!mInlineSpellChecker && autoCreate) {
|
2005-02-01 21:12:53 +00:00
|
|
|
mInlineSpellChecker = do_CreateInstance(MOZ_INLINESPELLCHECKER_CONTRACTID, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2008-05-27 17:55:13 +00:00
|
|
|
}
|
2005-02-01 21:12:53 +00:00
|
|
|
|
2008-05-27 17:55:13 +00:00
|
|
|
if (mInlineSpellChecker) {
|
2005-02-01 21:12:53 +00:00
|
|
|
rv = mInlineSpellChecker->Init(this);
|
2006-07-21 01:15:57 +00:00
|
|
|
if (NS_FAILED(rv))
|
|
|
|
mInlineSpellChecker = nsnull;
|
2005-02-01 21:12:53 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
2006-07-21 01:15:57 +00:00
|
|
|
NS_IF_ADDREF(*aInlineSpellChecker = mInlineSpellChecker);
|
|
|
|
|
2005-02-01 21:12:53 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-03-24 00:26:47 +00:00
|
|
|
|
2006-07-29 00:04:40 +00:00
|
|
|
NS_IMETHODIMP nsEditor::SyncRealTimeSpell()
|
|
|
|
{
|
2010-05-19 23:22:19 +00:00
|
|
|
NS_TIME_FUNCTION;
|
|
|
|
|
2006-07-29 00:04:40 +00:00
|
|
|
PRBool enable = GetDesiredSpellCheckState();
|
|
|
|
|
|
|
|
nsCOMPtr<nsIInlineSpellChecker> spellChecker;
|
|
|
|
GetInlineSpellChecker(enable, getter_AddRefs(spellChecker));
|
|
|
|
|
|
|
|
if (spellChecker) {
|
|
|
|
spellChecker->SetEnableRealTimeSpell(enable);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsEditor::SetSpellcheckUserOverride(PRBool enable)
|
|
|
|
{
|
|
|
|
mSpellcheckCheckboxState = enable ? eTriTrue : eTriFalse;
|
|
|
|
|
|
|
|
return SyncRealTimeSpell();
|
|
|
|
}
|
|
|
|
|
2000-03-24 00:26:47 +00:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark main node manipulation routines
|
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
2002-03-23 22:16:54 +00:00
|
|
|
NS_IMETHODIMP nsEditor::CreateNode(const nsAString& aTag,
|
1999-08-09 01:37:50 +00:00
|
|
|
nsIDOMNode * aParent,
|
|
|
|
PRInt32 aPosition,
|
|
|
|
nsIDOMNode ** aNewNode)
|
1999-07-01 19:32:35 +00:00
|
|
|
{
|
1999-11-25 00:16:56 +00:00
|
|
|
PRInt32 i;
|
|
|
|
|
1999-12-07 08:30:19 +00:00
|
|
|
nsAutoRules beginRulesSniffing(this, kOpCreateNode, nsIEditor::eNext);
|
|
|
|
|
2006-10-09 15:41:26 +00:00
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->WillCreateNode(aTag, aParent, aPosition);
|
1999-11-25 00:16:56 +00:00
|
|
|
|
2007-07-02 14:01:27 +00:00
|
|
|
nsRefPtr<CreateElementTxn> txn;
|
|
|
|
nsresult result = CreateTxnForCreateElement(aTag, aParent, aPosition,
|
|
|
|
getter_AddRefs(txn));
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{
|
2003-04-04 20:50:25 +00:00
|
|
|
result = DoTransaction(txn);
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{
|
|
|
|
result = txn->GetNewNode(aNewNode);
|
2001-03-09 14:23:59 +00:00
|
|
|
NS_ASSERTION((NS_SUCCEEDED(result)), "GetNewNode can't fail if txn::DoTransaction succeeded.");
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
}
|
1999-11-25 00:16:56 +00:00
|
|
|
|
2000-08-26 04:03:50 +00:00
|
|
|
mRangeUpdater.SelAdjCreateNode(aParent, aPosition);
|
2000-03-24 00:26:47 +00:00
|
|
|
|
2006-10-09 15:41:26 +00:00
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->DidCreateNode(aTag, *aNewNode, aParent, aPosition, result);
|
1999-11-25 00:16:56 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
return result;
|
1999-07-02 03:57:50 +00:00
|
|
|
}
|
1999-07-01 19:32:35 +00:00
|
|
|
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_IMETHODIMP nsEditor::InsertNode(nsIDOMNode * aNode,
|
|
|
|
nsIDOMNode * aParent,
|
|
|
|
PRInt32 aPosition)
|
1999-07-02 03:57:50 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
PRInt32 i;
|
1999-12-07 08:30:19 +00:00
|
|
|
nsAutoRules beginRulesSniffing(this, kOpInsertNode, nsIEditor::eNext);
|
1999-07-02 03:57:50 +00:00
|
|
|
|
2006-10-09 15:41:26 +00:00
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->WillInsertNode(aNode, aParent, aPosition);
|
1999-07-01 19:32:35 +00:00
|
|
|
|
2007-07-02 14:01:27 +00:00
|
|
|
nsRefPtr<InsertElementTxn> txn;
|
|
|
|
nsresult result = CreateTxnForInsertElement(aNode, aParent, aPosition,
|
|
|
|
getter_AddRefs(txn));
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_SUCCEEDED(result)) {
|
2003-04-04 20:50:25 +00:00
|
|
|
result = DoTransaction(txn);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
1999-07-01 19:32:35 +00:00
|
|
|
|
2000-08-26 04:03:50 +00:00
|
|
|
mRangeUpdater.SelAdjInsertNode(aParent, aPosition);
|
2000-03-24 00:26:47 +00:00
|
|
|
|
2006-10-09 15:41:26 +00:00
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->DidInsertNode(aNode, aParent, aPosition, result);
|
1999-08-09 01:37:50 +00:00
|
|
|
|
|
|
|
return result;
|
1999-07-02 03:57:50 +00:00
|
|
|
}
|
1999-07-01 19:32:35 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::SplitNode(nsIDOMNode * aNode,
|
|
|
|
PRInt32 aOffset,
|
|
|
|
nsIDOMNode **aNewLeftNode)
|
1999-07-02 03:57:50 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
PRInt32 i;
|
1999-12-07 08:30:19 +00:00
|
|
|
nsAutoRules beginRulesSniffing(this, kOpSplitNode, nsIEditor::eNext);
|
1999-07-01 19:32:35 +00:00
|
|
|
|
2006-10-09 15:41:26 +00:00
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->WillSplitNode(aNode, aOffset);
|
1999-07-01 19:32:35 +00:00
|
|
|
|
2007-07-02 14:01:27 +00:00
|
|
|
nsRefPtr<SplitElementTxn> txn;
|
|
|
|
nsresult result = CreateTxnForSplitNode(aNode, aOffset, getter_AddRefs(txn));
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{
|
2003-04-04 20:50:25 +00:00
|
|
|
result = DoTransaction(txn);
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{
|
|
|
|
result = txn->GetNewNode(aNewLeftNode);
|
|
|
|
NS_ASSERTION((NS_SUCCEEDED(result)), "result must succeeded for GetNewNode");
|
|
|
|
}
|
|
|
|
}
|
1999-07-01 19:32:35 +00:00
|
|
|
|
2000-08-26 04:03:50 +00:00
|
|
|
mRangeUpdater.SelAdjSplitNode(aNode, aOffset, *aNewLeftNode);
|
2000-03-24 00:26:47 +00:00
|
|
|
|
2006-10-09 15:41:26 +00:00
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
2006-10-09 15:41:26 +00:00
|
|
|
nsIDOMNode *ptr = *aNewLeftNode;
|
|
|
|
mActionListeners[i]->DidSplitNode(aNode, aOffset, ptr, result);
|
2000-03-24 00:26:47 +00:00
|
|
|
}
|
1999-09-10 18:54:13 +00:00
|
|
|
|
2000-03-24 00:26:47 +00:00
|
|
|
return result;
|
|
|
|
}
|
1999-09-10 18:54:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::JoinNodes(nsIDOMNode * aLeftNode,
|
|
|
|
nsIDOMNode * aRightNode,
|
|
|
|
nsIDOMNode * aParent)
|
|
|
|
{
|
2000-03-24 00:26:47 +00:00
|
|
|
PRInt32 i, offset;
|
1999-12-07 08:30:19 +00:00
|
|
|
nsAutoRules beginRulesSniffing(this, kOpJoinNode, nsIEditor::ePrevious);
|
1999-07-01 19:32:35 +00:00
|
|
|
|
2000-03-24 00:26:47 +00:00
|
|
|
// remember some values; later used for saved selection updating.
|
|
|
|
// find the offset between the nodes to be joined.
|
|
|
|
nsresult result = GetChildOffset(aRightNode, aParent, offset);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2000-03-24 00:26:47 +00:00
|
|
|
// find the number of children of the lefthand node
|
2003-06-30 17:28:52 +00:00
|
|
|
PRUint32 oldLeftNodeLen;
|
2000-03-24 00:26:47 +00:00
|
|
|
result = GetLengthOfDOMNode(aLeftNode, oldLeftNodeLen);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2000-03-24 00:26:47 +00:00
|
|
|
|
2006-10-09 15:41:26 +00:00
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->WillJoinNodes(aLeftNode, aRightNode, aParent);
|
1999-07-01 19:32:35 +00:00
|
|
|
|
2007-07-02 14:01:27 +00:00
|
|
|
nsRefPtr<JoinElementTxn> txn;
|
|
|
|
result = CreateTxnForJoinNode(aLeftNode, aRightNode, getter_AddRefs(txn));
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_SUCCEEDED(result)) {
|
2003-04-04 20:50:25 +00:00
|
|
|
result = DoTransaction(txn);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
1999-07-01 19:32:35 +00:00
|
|
|
|
2000-08-26 04:03:50 +00:00
|
|
|
mRangeUpdater.SelAdjJoinNodes(aLeftNode, aRightNode, aParent, offset, (PRInt32)oldLeftNodeLen);
|
2000-03-24 00:26:47 +00:00
|
|
|
|
2006-10-09 15:41:26 +00:00
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->DidJoinNodes(aLeftNode, aRightNode, aParent, result);
|
1999-07-01 19:32:35 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
return result;
|
|
|
|
}
|
1999-07-01 19:32:35 +00:00
|
|
|
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_IMETHODIMP nsEditor::DeleteNode(nsIDOMNode * aElement)
|
|
|
|
{
|
2000-03-24 00:26:47 +00:00
|
|
|
PRInt32 i, offset;
|
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
1999-12-07 08:30:19 +00:00
|
|
|
nsAutoRules beginRulesSniffing(this, kOpCreateNode, nsIEditor::ePrevious);
|
1999-07-01 19:32:35 +00:00
|
|
|
|
2000-03-24 00:26:47 +00:00
|
|
|
// save node location for selection updating code.
|
2000-12-09 04:46:08 +00:00
|
|
|
nsresult result = GetNodeLocation(aElement, address_of(parent), &offset);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2000-03-24 00:26:47 +00:00
|
|
|
|
2006-10-09 15:41:26 +00:00
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->WillDeleteNode(aElement);
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2007-07-02 14:01:27 +00:00
|
|
|
nsRefPtr<DeleteElementTxn> txn;
|
|
|
|
result = CreateTxnForDeleteElement(aElement, getter_AddRefs(txn));
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_SUCCEEDED(result)) {
|
2003-04-04 20:50:25 +00:00
|
|
|
result = DoTransaction(txn);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
1999-07-01 19:32:35 +00:00
|
|
|
|
2006-10-09 15:41:26 +00:00
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->DidDeleteNode(aElement, result);
|
1999-07-01 19:32:35 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
return result;
|
1999-07-01 19:32:35 +00:00
|
|
|
}
|
|
|
|
|
2000-03-24 00:26:47 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// ReplaceContainer: replace inNode with a new node (outNode) which is contructed
|
|
|
|
// to be of type aNodeType. Put inNodes children into outNode.
|
|
|
|
// Callers responsibility to make sure inNode's children can
|
|
|
|
// go in outNode.
|
|
|
|
nsresult
|
|
|
|
nsEditor::ReplaceContainer(nsIDOMNode *inNode,
|
|
|
|
nsCOMPtr<nsIDOMNode> *outNode,
|
2002-03-23 22:16:54 +00:00
|
|
|
const nsAString &aNodeType,
|
|
|
|
const nsAString *aAttribute,
|
|
|
|
const nsAString *aValue,
|
2000-06-22 05:39:54 +00:00
|
|
|
PRBool aCloneAttributes)
|
2000-03-24 00:26:47 +00:00
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(inNode && outNode, NS_ERROR_NULL_POINTER);
|
2000-03-24 00:26:47 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
PRInt32 offset;
|
2003-06-30 17:28:52 +00:00
|
|
|
nsresult res = GetNodeLocation(inNode, address_of(parent), &offset);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-03-24 00:26:47 +00:00
|
|
|
|
|
|
|
// create new container
|
2000-07-13 23:15:41 +00:00
|
|
|
nsCOMPtr<nsIContent> newContent;
|
|
|
|
|
|
|
|
//new call to use instead to get proper HTML element, bug# 39919
|
2000-07-14 18:38:24 +00:00
|
|
|
res = CreateHTMLContent(aNodeType, getter_AddRefs(newContent));
|
2003-06-30 17:28:52 +00:00
|
|
|
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(newContent);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-07-13 23:15:41 +00:00
|
|
|
*outNode = do_QueryInterface(elem);
|
2000-03-24 00:26:47 +00:00
|
|
|
|
|
|
|
// set attribute if needed
|
|
|
|
if (aAttribute && aValue && !aAttribute->IsEmpty())
|
|
|
|
{
|
|
|
|
res = elem->SetAttribute(*aAttribute, *aValue);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-03-24 00:26:47 +00:00
|
|
|
}
|
2000-06-22 05:39:54 +00:00
|
|
|
if (aCloneAttributes)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode>newNode = do_QueryInterface(elem);
|
|
|
|
res = CloneAttributes(newNode, inNode);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-06-22 05:39:54 +00:00
|
|
|
}
|
2000-03-24 00:26:47 +00:00
|
|
|
|
|
|
|
// notify our internal selection state listener
|
2000-07-01 00:37:12 +00:00
|
|
|
// (Note: A nsAutoSelectionReset object must be created
|
2000-08-26 04:03:50 +00:00
|
|
|
// before calling this to initialize mRangeUpdater)
|
|
|
|
nsAutoReplaceContainerSelNotify selStateNotify(mRangeUpdater, inNode, *outNode);
|
2000-03-24 00:26:47 +00:00
|
|
|
{
|
2006-05-15 19:35:12 +00:00
|
|
|
nsAutoTxnsConserveSelection conserveSelection(this);
|
|
|
|
nsCOMPtr<nsIDOMNode> child;
|
|
|
|
PRBool bHasMoreChildren;
|
2000-03-24 00:26:47 +00:00
|
|
|
inNode->HasChildNodes(&bHasMoreChildren);
|
2006-05-15 19:35:12 +00:00
|
|
|
while (bHasMoreChildren)
|
|
|
|
{
|
|
|
|
inNode->GetFirstChild(getter_AddRefs(child));
|
|
|
|
res = DeleteNode(child);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-06-22 05:39:54 +00:00
|
|
|
|
2006-05-15 19:35:12 +00:00
|
|
|
res = InsertNode(child, *outNode, -1);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2006-05-15 19:35:12 +00:00
|
|
|
inNode->HasChildNodes(&bHasMoreChildren);
|
|
|
|
}
|
|
|
|
}
|
2000-07-01 00:37:12 +00:00
|
|
|
// insert new container into tree
|
|
|
|
res = InsertNode( *outNode, parent, offset);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-03-24 00:26:47 +00:00
|
|
|
|
2000-06-22 05:39:54 +00:00
|
|
|
// delete old container
|
|
|
|
return DeleteNode(inNode);
|
2000-03-24 00:26:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2003-06-30 17:28:52 +00:00
|
|
|
// RemoveContainer: remove inNode, reparenting its children into their
|
2000-03-24 00:26:47 +00:00
|
|
|
// the parent of inNode
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsEditor::RemoveContainer(nsIDOMNode *inNode)
|
1999-07-14 18:54:29 +00:00
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(inNode, NS_ERROR_NULL_POINTER);
|
2000-03-24 00:26:47 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
PRInt32 offset;
|
|
|
|
|
2003-06-30 17:28:52 +00:00
|
|
|
nsresult res = GetNodeLocation(inNode, address_of(parent), &offset);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-03-24 00:26:47 +00:00
|
|
|
|
|
|
|
// loop through the child nodes of inNode and promote them
|
|
|
|
// into inNode's parent.
|
|
|
|
PRBool bHasMoreChildren;
|
|
|
|
inNode->HasChildNodes(&bHasMoreChildren);
|
|
|
|
nsCOMPtr<nsIDOMNodeList> nodeList;
|
|
|
|
res = inNode->GetChildNodes(getter_AddRefs(nodeList));
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(nodeList, NS_ERROR_NULL_POINTER);
|
2003-06-30 17:28:52 +00:00
|
|
|
PRUint32 nodeOrigLen;
|
2000-03-24 00:26:47 +00:00
|
|
|
nodeList->GetLength(&nodeOrigLen);
|
|
|
|
|
|
|
|
// notify our internal selection state listener
|
2000-08-26 04:03:50 +00:00
|
|
|
nsAutoRemoveContainerSelNotify selNotify(mRangeUpdater, inNode, parent, offset, nodeOrigLen);
|
2000-03-24 00:26:47 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> child;
|
|
|
|
while (bHasMoreChildren)
|
|
|
|
{
|
|
|
|
inNode->GetLastChild(getter_AddRefs(child));
|
|
|
|
res = DeleteNode(child);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-03-24 00:26:47 +00:00
|
|
|
res = InsertNode(child, parent, offset);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-03-24 00:26:47 +00:00
|
|
|
inNode->HasChildNodes(&bHasMoreChildren);
|
|
|
|
}
|
2003-06-30 17:28:52 +00:00
|
|
|
return DeleteNode(inNode);
|
1999-07-14 18:54:29 +00:00
|
|
|
}
|
|
|
|
|
2000-03-24 00:26:47 +00:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// InsertContainerAbove: insert a new parent for inNode, returned in outNode,
|
|
|
|
// which is contructed to be of type aNodeType. outNode becomes
|
|
|
|
// a child of inNode's earlier parent.
|
|
|
|
// Callers responsibility to make sure inNode's can be child
|
|
|
|
// of outNode, and outNode can be child of old parent.
|
|
|
|
nsresult
|
|
|
|
nsEditor::InsertContainerAbove( nsIDOMNode *inNode,
|
|
|
|
nsCOMPtr<nsIDOMNode> *outNode,
|
2002-03-23 22:16:54 +00:00
|
|
|
const nsAString &aNodeType,
|
|
|
|
const nsAString *aAttribute,
|
|
|
|
const nsAString *aValue)
|
1999-07-14 18:54:29 +00:00
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(inNode && outNode, NS_ERROR_NULL_POINTER);
|
2000-03-24 00:26:47 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
PRInt32 offset;
|
2003-06-30 17:28:52 +00:00
|
|
|
nsresult res = GetNodeLocation(inNode, address_of(parent), &offset);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-03-24 00:26:47 +00:00
|
|
|
|
|
|
|
// create new container
|
2000-07-13 23:15:41 +00:00
|
|
|
nsCOMPtr<nsIContent> newContent;
|
|
|
|
|
|
|
|
//new call to use instead to get proper HTML element, bug# 39919
|
2000-07-14 18:38:24 +00:00
|
|
|
res = CreateHTMLContent(aNodeType, getter_AddRefs(newContent));
|
2003-06-30 17:28:52 +00:00
|
|
|
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(newContent);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-03-24 00:26:47 +00:00
|
|
|
*outNode = do_QueryInterface(elem);
|
|
|
|
|
|
|
|
// set attribute if needed
|
|
|
|
if (aAttribute && aValue && !aAttribute->IsEmpty())
|
|
|
|
{
|
|
|
|
res = elem->SetAttribute(*aAttribute, *aValue);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-03-24 00:26:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// notify our internal selection state listener
|
2000-08-26 04:03:50 +00:00
|
|
|
nsAutoInsertContainerSelNotify selNotify(mRangeUpdater);
|
2000-03-24 00:26:47 +00:00
|
|
|
|
|
|
|
// put inNode in new parent, outNode
|
|
|
|
res = DeleteNode(inNode);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2006-05-15 19:35:12 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
nsAutoTxnsConserveSelection conserveSelection(this);
|
|
|
|
res = InsertNode(inNode, *outNode, 0);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2006-05-15 19:35:12 +00:00
|
|
|
}
|
|
|
|
|
2000-03-24 00:26:47 +00:00
|
|
|
// put new parent in doc
|
2003-06-30 17:28:52 +00:00
|
|
|
return InsertNode(*outNode, parent, offset);
|
2000-03-24 00:26:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// MoveNode: move aNode to {aParent,aOffset}
|
|
|
|
nsresult
|
|
|
|
nsEditor::MoveNode(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aNode && aParent, NS_ERROR_NULL_POINTER);
|
2003-06-30 17:28:52 +00:00
|
|
|
|
2000-03-24 00:26:47 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> oldParent;
|
|
|
|
PRInt32 oldOffset;
|
2003-06-30 17:28:52 +00:00
|
|
|
nsresult res = GetNodeLocation(aNode, address_of(oldParent), &oldOffset);
|
2000-03-24 00:26:47 +00:00
|
|
|
|
|
|
|
if (aOffset == -1)
|
|
|
|
{
|
|
|
|
PRUint32 unsignedOffset;
|
|
|
|
// magic value meaning "move to end of aParent"
|
|
|
|
res = GetLengthOfDOMNode(aParent, unsignedOffset);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-03-24 00:26:47 +00:00
|
|
|
aOffset = (PRInt32)unsignedOffset;
|
|
|
|
}
|
|
|
|
|
2003-06-30 17:28:52 +00:00
|
|
|
// don't do anything if it's already in right place
|
2000-03-24 00:26:47 +00:00
|
|
|
if ((aParent == oldParent.get()) && (oldOffset == aOffset)) return NS_OK;
|
|
|
|
|
|
|
|
// notify our internal selection state listener
|
2000-08-26 04:03:50 +00:00
|
|
|
nsAutoMoveNodeSelNotify selNotify(mRangeUpdater, oldParent, oldOffset, aParent, aOffset);
|
2000-03-24 00:26:47 +00:00
|
|
|
|
2003-06-30 17:28:52 +00:00
|
|
|
// need to adjust aOffset if we are moving aNode further along in its current parent
|
2000-03-24 00:26:47 +00:00
|
|
|
if ((aParent == oldParent.get()) && (oldOffset < aOffset))
|
|
|
|
{
|
|
|
|
aOffset--; // this is because when we delete aNode, it will make the offsets after it off by one
|
|
|
|
}
|
|
|
|
|
|
|
|
// put aNode in new parent
|
|
|
|
res = DeleteNode(aNode);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2003-06-30 17:28:52 +00:00
|
|
|
return InsertNode(aNode, aParent, aOffset);
|
1999-07-14 18:54:29 +00:00
|
|
|
}
|
|
|
|
|
2000-07-16 06:36:27 +00:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark editor observer maintainance
|
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::AddEditorObserver(nsIEditorObserver *aObserver)
|
|
|
|
{
|
|
|
|
// we don't keep ownership of the observers. They must
|
|
|
|
// remove themselves as observers before they are destroyed.
|
|
|
|
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aObserver, NS_ERROR_NULL_POINTER);
|
2000-07-16 06:36:27 +00:00
|
|
|
|
|
|
|
// Make sure the listener isn't already on the list
|
2006-10-09 15:41:26 +00:00
|
|
|
if (mEditorObservers.IndexOf(aObserver) == -1)
|
2000-07-16 06:36:27 +00:00
|
|
|
{
|
2006-10-09 15:41:26 +00:00
|
|
|
if (!mEditorObservers.AppendObject(aObserver))
|
2000-07-16 06:36:27 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::RemoveEditorObserver(nsIEditorObserver *aObserver)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aObserver, NS_ERROR_FAILURE);
|
2000-07-16 06:36:27 +00:00
|
|
|
|
2006-10-09 15:41:26 +00:00
|
|
|
if (!mEditorObservers.RemoveObject(aObserver))
|
2000-07-16 06:36:27 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nsEditor::NotifyEditorObservers(void)
|
|
|
|
{
|
2006-10-09 15:41:26 +00:00
|
|
|
for (PRInt32 i = 0; i < mEditorObservers.Count(); i++)
|
|
|
|
mEditorObservers[i]->EditAction();
|
2000-07-16 06:36:27 +00:00
|
|
|
}
|
|
|
|
|
2000-03-24 00:26:47 +00:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark action listener maintainance
|
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
1999-04-27 17:14:28 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::AddEditActionListener(nsIEditActionListener *aListener)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aListener, NS_ERROR_NULL_POINTER);
|
1999-04-27 17:14:28 +00:00
|
|
|
|
2000-07-16 06:36:27 +00:00
|
|
|
// Make sure the listener isn't already on the list
|
2006-10-09 15:41:26 +00:00
|
|
|
if (mActionListeners.IndexOf(aListener) == -1)
|
2000-07-16 06:36:27 +00:00
|
|
|
{
|
2006-10-09 15:41:26 +00:00
|
|
|
if (!mActionListeners.AppendObject(aListener))
|
2000-07-16 06:36:27 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
1999-04-27 17:14:28 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
|
1999-04-27 17:14:28 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::RemoveEditActionListener(nsIEditActionListener *aListener)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aListener, NS_ERROR_FAILURE);
|
1999-04-27 17:14:28 +00:00
|
|
|
|
2006-10-09 15:41:26 +00:00
|
|
|
if (!mActionListeners.RemoveObject(aListener))
|
1999-04-27 17:14:28 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-16 06:36:27 +00:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark docstate listener maintainance
|
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
1999-07-28 02:55:40 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::AddDocumentStateListener(nsIDocumentStateListener *aListener)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aListener, NS_ERROR_NULL_POINTER);
|
1999-07-28 02:55:40 +00:00
|
|
|
|
2006-10-09 15:41:26 +00:00
|
|
|
if (mDocStateListeners.IndexOf(aListener) == -1)
|
1999-07-28 02:55:40 +00:00
|
|
|
{
|
2006-10-09 15:41:26 +00:00
|
|
|
if (!mDocStateListeners.AppendObject(aListener))
|
|
|
|
return NS_ERROR_FAILURE;
|
1999-07-28 02:55:40 +00:00
|
|
|
}
|
|
|
|
|
2006-10-09 15:41:26 +00:00
|
|
|
return NS_OK;
|
1999-07-28 02:55:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::RemoveDocumentStateListener(nsIDocumentStateListener *aListener)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aListener, NS_ERROR_NULL_POINTER);
|
1999-07-28 02:55:40 +00:00
|
|
|
|
2006-10-09 15:41:26 +00:00
|
|
|
if (!mDocStateListeners.RemoveObject(aListener))
|
|
|
|
return NS_ERROR_FAILURE;
|
1999-07-28 02:55:40 +00:00
|
|
|
|
2006-10-09 15:41:26 +00:00
|
|
|
return NS_OK;
|
1999-07-28 02:55:40 +00:00
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2000-03-24 00:26:47 +00:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark misc
|
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
2002-03-25 22:39:19 +00:00
|
|
|
NS_IMETHODIMP nsEditor::OutputToString(const nsAString& aFormatType,
|
|
|
|
PRUint32 aFlags,
|
|
|
|
nsAString& aOutputString)
|
2000-03-24 00:26:47 +00:00
|
|
|
{
|
|
|
|
// these should be implemented by derived classes.
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2001-01-08 21:01:29 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::OutputToStream(nsIOutputStream* aOutputStream,
|
2002-03-23 22:16:54 +00:00
|
|
|
const nsAString& aFormatType,
|
2003-07-08 20:38:51 +00:00
|
|
|
const nsACString& aCharsetOverride,
|
2001-01-08 21:01:29 +00:00
|
|
|
PRUint32 aFlags)
|
2000-03-24 00:26:47 +00:00
|
|
|
{
|
|
|
|
// these should be implemented by derived classes.
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
1999-07-28 02:55:40 +00:00
|
|
|
NS_IMETHODIMP
|
1999-08-09 01:37:50 +00:00
|
|
|
nsEditor::DumpContentTree()
|
1999-07-28 02:55:40 +00:00
|
|
|
{
|
2001-10-16 05:31:36 +00:00
|
|
|
#ifdef DEBUG
|
2005-03-24 19:00:01 +00:00
|
|
|
nsCOMPtr<nsIContent> root = do_QueryInterface(mRootElement);
|
2000-06-29 09:23:41 +00:00
|
|
|
if (root) root->List(stdout);
|
2001-10-16 05:31:36 +00:00
|
|
|
#endif
|
1999-08-09 01:37:50 +00:00
|
|
|
return NS_OK;
|
1999-07-28 02:55:40 +00:00
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
|
1999-07-28 02:55:40 +00:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 00:45:26 +00:00
|
|
|
nsEditor::DebugDumpContent()
|
1999-07-28 02:55:40 +00:00
|
|
|
{
|
2001-10-16 05:31:36 +00:00
|
|
|
#ifdef DEBUG
|
2003-06-30 18:55:06 +00:00
|
|
|
nsCOMPtr<nsIDOMHTMLDocument> doc = do_QueryReferent(mDocWeak);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
|
2003-06-30 18:55:06 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMHTMLElement>bodyElem;
|
|
|
|
doc->GetBody(getter_AddRefs(bodyElem));
|
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(bodyElem);
|
|
|
|
if (content)
|
|
|
|
content->List();
|
2001-10-16 05:31:36 +00:00
|
|
|
#endif
|
1999-08-09 01:37:50 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-07-28 02:55:40 +00:00
|
|
|
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::DebugUnitTests(PRInt32 *outNumTests, PRInt32 *outNumTestsFailed)
|
|
|
|
{
|
2001-10-16 05:31:36 +00:00
|
|
|
#ifdef DEBUG
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_NOTREACHED("This should never get called. Overridden by subclasses");
|
2001-10-16 05:31:36 +00:00
|
|
|
#endif
|
1999-07-28 02:55:40 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-08-26 04:03:50 +00:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark support for selection preservation
|
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsEditor::ArePreservingSelection()
|
|
|
|
{
|
2003-06-30 17:28:52 +00:00
|
|
|
return !(mSavedSel.IsEmpty());
|
2000-08-26 04:03:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2000-09-14 11:45:01 +00:00
|
|
|
nsEditor::PreserveSelectionAcrossActions(nsISelection *aSel)
|
2000-08-26 04:03:50 +00:00
|
|
|
{
|
|
|
|
mSavedSel.SaveSelection(aSel);
|
|
|
|
mRangeUpdater.RegisterSelectionState(mSavedSel);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2000-09-14 11:45:01 +00:00
|
|
|
nsEditor::RestorePreservedSelection(nsISelection *aSel)
|
2000-08-26 04:03:50 +00:00
|
|
|
{
|
|
|
|
if (mSavedSel.IsEmpty()) return NS_ERROR_FAILURE;
|
|
|
|
mSavedSel.RestoreSelection(aSel);
|
|
|
|
StopPreservingSelection();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsEditor::StopPreservingSelection()
|
|
|
|
{
|
|
|
|
mRangeUpdater.DropSelectionState(mSavedSel);
|
|
|
|
mSavedSel.MakeEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
2010-06-30 04:05:12 +00:00
|
|
|
#pragma mark IME event handlers
|
1999-08-09 01:37:50 +00:00
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
2010-06-30 04:05:12 +00:00
|
|
|
nsresult
|
|
|
|
nsEditor::BeginIMEComposition()
|
1999-12-07 01:29:00 +00:00
|
|
|
{
|
|
|
|
mInIMEMode = PR_TRUE;
|
2010-06-30 04:05:12 +00:00
|
|
|
if (mPhonetic) {
|
2002-12-17 23:38:04 +00:00
|
|
|
mPhonetic->Truncate(0);
|
2010-06-30 04:05:12 +00:00
|
|
|
}
|
2010-04-10 09:24:35 +00:00
|
|
|
return NS_OK;
|
1999-12-07 01:29:00 +00:00
|
|
|
}
|
1999-02-18 23:01:06 +00:00
|
|
|
|
2010-06-30 04:05:12 +00:00
|
|
|
nsresult
|
|
|
|
nsEditor::EndIMEComposition()
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(mInIMEMode, NS_OK); // nothing to do
|
2010-06-30 04:05:12 +00:00
|
|
|
|
|
|
|
nsresult rv = NS_OK;
|
1999-10-26 18:54:47 +00:00
|
|
|
|
|
|
|
// commit the IME transaction..we can get at it via the transaction mgr.
|
|
|
|
// Note that this means IME won't work without an undo stack!
|
2010-06-30 04:05:12 +00:00
|
|
|
if (mTxnMgr) {
|
2001-03-09 14:23:59 +00:00
|
|
|
nsCOMPtr<nsITransaction> txn;
|
2010-06-30 04:05:12 +00:00
|
|
|
rv = mTxnMgr->PeekUndoStack(getter_AddRefs(txn));
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "PeekUndoStack() failed");
|
1999-10-26 18:54:47 +00:00
|
|
|
nsCOMPtr<nsIAbsorbingTransaction> plcTxn = do_QueryInterface(txn);
|
2010-06-30 04:05:12 +00:00
|
|
|
if (plcTxn) {
|
|
|
|
rv = plcTxn->Commit();
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv),
|
|
|
|
"nsIAbsorbingTransaction::Commit() failed");
|
1999-10-18 14:48:41 +00:00
|
|
|
}
|
1999-08-25 10:51:55 +00:00
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
|
1999-08-25 10:51:55 +00:00
|
|
|
/* reset the data we need to construct a transaction */
|
2010-06-30 04:05:12 +00:00
|
|
|
mIMETextNode = nsnull;
|
1999-08-25 10:51:55 +00:00
|
|
|
mIMETextOffset = 0;
|
|
|
|
mIMEBufferLength = 0;
|
1999-10-26 18:54:47 +00:00
|
|
|
mInIMEMode = PR_FALSE;
|
2002-12-22 01:51:14 +00:00
|
|
|
mIsIMEComposing = PR_FALSE;
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2000-07-16 06:36:27 +00:00
|
|
|
// notify editor observers of action
|
|
|
|
NotifyEditorObservers();
|
|
|
|
|
2010-06-30 04:05:12 +00:00
|
|
|
return rv;
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
|
2010-06-30 04:05:12 +00:00
|
|
|
|
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark nsIPhonetic
|
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
1999-02-12 17:18:58 +00:00
|
|
|
|
2002-12-17 23:38:04 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::GetPhonetic(nsAString& aPhonetic)
|
|
|
|
{
|
|
|
|
if (mPhonetic)
|
|
|
|
aPhonetic = *mPhonetic;
|
|
|
|
else
|
|
|
|
aPhonetic.Truncate(0);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-06-30 04:05:12 +00:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark nsIEditorIMESupport
|
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2000-07-18 22:11:31 +00:00
|
|
|
static nsresult
|
2009-12-24 21:20:06 +00:00
|
|
|
GetEditorContentWindow(nsIDOMElement *aRoot, nsIWidget **aResult)
|
2000-07-18 22:11:31 +00:00
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aRoot && aResult, NS_ERROR_NULL_POINTER);
|
2000-07-18 22:11:31 +00:00
|
|
|
|
|
|
|
*aResult = 0;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aRoot);
|
|
|
|
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
|
2000-07-18 22:11:31 +00:00
|
|
|
|
2005-08-22 22:24:29 +00:00
|
|
|
// Not ref counted
|
2009-12-24 21:20:06 +00:00
|
|
|
nsIFrame *frame = content->GetPrimaryFrame();
|
2000-07-18 22:11:31 +00:00
|
|
|
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
|
2000-07-18 22:11:31 +00:00
|
|
|
|
2010-07-02 19:11:04 +00:00
|
|
|
*aResult = frame->GetNearestWidget();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(*aResult, NS_ERROR_FAILURE);
|
2000-07-18 22:11:31 +00:00
|
|
|
|
2003-06-24 13:39:15 +00:00
|
|
|
NS_ADDREF(*aResult);
|
2000-07-18 22:11:31 +00:00
|
|
|
return NS_OK;
|
1999-12-08 03:39:36 +00:00
|
|
|
}
|
|
|
|
|
2004-09-12 05:00:57 +00:00
|
|
|
nsresult
|
2008-07-14 02:56:18 +00:00
|
|
|
nsEditor::GetWidget(nsIWidget **aWidget)
|
2004-09-12 05:00:57 +00:00
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aWidget, NS_ERROR_NULL_POINTER);
|
2008-07-14 02:56:18 +00:00
|
|
|
*aWidget = nsnull;
|
2004-09-12 05:00:57 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIWidget> widget;
|
2009-12-24 21:20:06 +00:00
|
|
|
nsresult res = GetEditorContentWindow(GetRoot(), getter_AddRefs(widget));
|
2010-06-17 20:44:35 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(widget, NS_ERROR_NOT_AVAILABLE);
|
2004-09-12 05:00:57 +00:00
|
|
|
|
2008-07-14 02:56:18 +00:00
|
|
|
NS_ADDREF(*aWidget = widget);
|
2004-09-12 05:00:57 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-12-08 03:39:36 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::ForceCompositionEnd()
|
|
|
|
{
|
|
|
|
|
|
|
|
// We can test mInIMEMode and do some optimization for Mac and Window
|
|
|
|
// Howerver, since UNIX support over-the-spot, we cannot rely on that
|
|
|
|
// flag for Unix.
|
|
|
|
// We should use nsILookAndFeel to resolve this
|
|
|
|
|
2003-04-04 13:26:12 +00:00
|
|
|
#if defined(XP_MAC) || defined(XP_MACOSX) || defined(XP_WIN) || defined(XP_OS2)
|
2010-04-19 12:20:30 +00:00
|
|
|
// XXXmnakano see bug 558976, ResetInputState() has two meaning which are
|
|
|
|
// "commit the composition" and "cursor is moved". This method name is
|
|
|
|
// "ForceCompositionEnd", so, ResetInputState() should be used only for the
|
|
|
|
// former here. However, ResetInputState() is also used for the latter here
|
|
|
|
// because even if we don't have composition, we call ResetInputState() on
|
|
|
|
// Linux. Currently, nsGtkIMModule can know the timing of the cursor move,
|
|
|
|
// so, the latter meaning should be gone and we should remove this #if.
|
1999-12-08 03:39:36 +00:00
|
|
|
if(! mInIMEMode)
|
|
|
|
return NS_OK;
|
|
|
|
#endif
|
|
|
|
|
2008-07-14 02:56:18 +00:00
|
|
|
nsCOMPtr<nsIWidget> widget;
|
|
|
|
nsresult res = GetWidget(getter_AddRefs(widget));
|
2010-06-17 20:44:35 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2004-09-12 05:00:57 +00:00
|
|
|
|
2008-07-14 02:56:18 +00:00
|
|
|
if (widget) {
|
|
|
|
res = widget->ResetInputState();
|
2010-06-17 20:44:35 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2004-09-12 05:00:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2005-11-14 23:55:24 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::GetPreferredIMEState(PRUint32 *aState)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aState);
|
2007-05-16 15:51:37 +00:00
|
|
|
*aState = nsIContent::IME_STATUS_ENABLE;
|
2000-07-18 22:11:31 +00:00
|
|
|
|
2010-04-12 02:35:18 +00:00
|
|
|
if (IsReadonly() || IsDisabled()) {
|
2005-11-14 23:55:24 +00:00
|
|
|
*aState = nsIContent::IME_STATUS_DISABLE;
|
2007-05-16 15:51:37 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(GetRoot());
|
|
|
|
NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
|
|
|
|
|
2009-12-24 21:20:06 +00:00
|
|
|
nsIFrame* frame = content->GetPrimaryFrame();
|
2007-05-16 15:51:37 +00:00
|
|
|
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
switch (frame->GetStyleUIReset()->mIMEMode) {
|
|
|
|
case NS_STYLE_IME_MODE_AUTO:
|
2010-04-12 02:35:18 +00:00
|
|
|
if (IsPasswordEditor())
|
2007-05-16 15:51:37 +00:00
|
|
|
*aState = nsIContent::IME_STATUS_PASSWORD;
|
|
|
|
break;
|
|
|
|
case NS_STYLE_IME_MODE_DISABLED:
|
|
|
|
// we should use password state for |ime-mode: disabled;|.
|
|
|
|
*aState = nsIContent::IME_STATUS_PASSWORD;
|
|
|
|
break;
|
|
|
|
case NS_STYLE_IME_MODE_ACTIVE:
|
|
|
|
*aState |= nsIContent::IME_STATUS_OPEN;
|
|
|
|
break;
|
|
|
|
case NS_STYLE_IME_MODE_INACTIVE:
|
|
|
|
*aState |= nsIContent::IME_STATUS_CLOSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
1999-12-08 03:39:36 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-07-11 19:51:36 +00:00
|
|
|
|
2008-02-20 07:18:53 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::GetComposing(PRBool* aResult)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aResult);
|
|
|
|
*aResult = IsIMEComposing();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
2000-03-24 00:26:47 +00:00
|
|
|
#pragma mark public nsEditor methods
|
1999-08-09 01:37:50 +00:00
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
/* Non-interface, public methods */
|
|
|
|
|
|
|
|
|
2010-06-17 05:29:40 +00:00
|
|
|
NS_IMETHODIMP
|
2005-03-24 19:00:01 +00:00
|
|
|
nsEditor::GetRootElement(nsIDOMElement **aRootElement)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
2010-06-17 05:29:40 +00:00
|
|
|
NS_ENSURE_ARG_POINTER(aRootElement);
|
|
|
|
NS_ENSURE_TRUE(mRootElement, NS_ERROR_NOT_AVAILABLE);
|
2009-12-17 04:46:30 +00:00
|
|
|
*aRootElement = mRootElement;
|
2005-03-24 19:00:01 +00:00
|
|
|
NS_ADDREF(*aRootElement);
|
2003-06-30 18:55:06 +00:00
|
|
|
return NS_OK;
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
|
1999-12-07 08:30:19 +00:00
|
|
|
/** All editor operations which alter the doc should be prefaced
|
|
|
|
* with a call to StartOperation, naming the action and direction */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
|
|
|
|
{
|
2000-08-14 02:39:37 +00:00
|
|
|
mAction = opID;
|
|
|
|
mDirection = aDirection;
|
1999-12-07 08:30:19 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** All editor operations which alter the doc should be followed
|
2000-08-14 02:39:37 +00:00
|
|
|
* with a call to EndOperation */
|
1999-12-07 08:30:19 +00:00
|
|
|
NS_IMETHODIMP
|
2000-08-14 02:39:37 +00:00
|
|
|
nsEditor::EndOperation()
|
1999-12-07 08:30:19 +00:00
|
|
|
{
|
2000-08-14 02:39:37 +00:00
|
|
|
mAction = nsnull;
|
|
|
|
mDirection = eNone;
|
1999-12-07 08:30:19 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2003-06-17 08:45:54 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::CloneAttribute(const nsAString & aAttribute,
|
|
|
|
nsIDOMNode *aDestNode, nsIDOMNode *aSourceNode)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aDestNode && aSourceNode, NS_ERROR_NULL_POINTER);
|
2003-06-17 08:45:54 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMElement> destElement = do_QueryInterface(aDestNode);
|
|
|
|
nsCOMPtr<nsIDOMElement> sourceElement = do_QueryInterface(aSourceNode);
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(destElement && sourceElement, NS_ERROR_NO_INTERFACE);
|
2003-06-17 08:45:54 +00:00
|
|
|
|
|
|
|
nsAutoString attrValue;
|
|
|
|
PRBool isAttrSet;
|
2003-06-30 18:55:06 +00:00
|
|
|
nsresult rv = GetAttributeValue(sourceElement,
|
|
|
|
aAttribute,
|
|
|
|
attrValue,
|
|
|
|
&isAttrSet);
|
2010-06-17 20:44:35 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2003-06-17 08:45:54 +00:00
|
|
|
if (isAttrSet)
|
|
|
|
rv = SetAttribute(destElement, aAttribute, attrValue);
|
|
|
|
else
|
|
|
|
rv = RemoveAttribute(destElement, aAttribute);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
// Objects must be DOM elements
|
|
|
|
NS_IMETHODIMP
|
1999-09-02 01:47:18 +00:00
|
|
|
nsEditor::CloneAttributes(nsIDOMNode *aDestNode, nsIDOMNode *aSourceNode)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aDestNode && aSourceNode, NS_ERROR_NULL_POINTER);
|
1999-03-02 05:30:53 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
nsCOMPtr<nsIDOMElement> destElement = do_QueryInterface(aDestNode);
|
|
|
|
nsCOMPtr<nsIDOMElement> sourceElement = do_QueryInterface(aSourceNode);
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(destElement && sourceElement, NS_ERROR_NO_INTERFACE);
|
1999-03-02 05:30:53 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
nsCOMPtr<nsIDOMNamedNodeMap> sourceAttributes;
|
|
|
|
sourceElement->GetAttributes(getter_AddRefs(sourceAttributes));
|
|
|
|
nsCOMPtr<nsIDOMNamedNodeMap> destAttributes;
|
|
|
|
destElement->GetAttributes(getter_AddRefs(destAttributes));
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(sourceAttributes && destAttributes, NS_ERROR_FAILURE);
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2000-04-14 03:19:31 +00:00
|
|
|
nsAutoEditBatch beginBatching(this);
|
|
|
|
|
2000-06-14 01:32:27 +00:00
|
|
|
// Use transaction system for undo only if destination
|
|
|
|
// is already in the document
|
2005-03-24 19:00:01 +00:00
|
|
|
nsIDOMElement *rootElement = GetRoot();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(rootElement, NS_ERROR_NULL_POINTER);
|
2000-06-14 01:32:27 +00:00
|
|
|
|
2003-06-30 17:28:52 +00:00
|
|
|
PRBool destInBody = PR_TRUE;
|
2005-03-24 19:00:01 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(rootElement);
|
2000-06-14 01:32:27 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> p = aDestNode;
|
2005-03-24 19:00:01 +00:00
|
|
|
while (p && p != rootNode)
|
2000-06-14 01:32:27 +00:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> tmp;
|
|
|
|
if (NS_FAILED(p->GetParentNode(getter_AddRefs(tmp))) || !tmp)
|
|
|
|
{
|
|
|
|
destInBody = PR_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
p = tmp;
|
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
PRUint32 sourceCount;
|
|
|
|
sourceAttributes->GetLength(&sourceCount);
|
|
|
|
PRUint32 i, destCount;
|
|
|
|
destAttributes->GetLength(&destCount);
|
2001-10-10 21:29:46 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> attrNode;
|
1999-08-09 01:37:50 +00:00
|
|
|
|
|
|
|
// Clear existing attributes
|
|
|
|
for (i = 0; i < destCount; i++)
|
|
|
|
{
|
1999-11-18 20:34:15 +00:00
|
|
|
// always remove item number 0 (first item in list)
|
2001-10-10 21:29:46 +00:00
|
|
|
if( NS_SUCCEEDED(destAttributes->Item(0, getter_AddRefs(attrNode))) && attrNode)
|
1999-03-02 05:30:53 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
nsCOMPtr<nsIDOMAttr> destAttribute = do_QueryInterface(attrNode);
|
|
|
|
if (destAttribute)
|
|
|
|
{
|
2000-04-14 03:19:31 +00:00
|
|
|
nsAutoString str;
|
|
|
|
if (NS_SUCCEEDED(destAttribute->GetName(str)))
|
2000-06-14 01:32:27 +00:00
|
|
|
{
|
|
|
|
if (destInBody)
|
|
|
|
RemoveAttribute(destElement, str);
|
|
|
|
else
|
|
|
|
destElement->RemoveAttribute(str);
|
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-03-24 19:00:01 +00:00
|
|
|
|
|
|
|
nsresult result = NS_OK;
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
// Set just the attributes that the source element has
|
|
|
|
for (i = 0; i < sourceCount; i++)
|
|
|
|
{
|
2001-10-10 21:29:46 +00:00
|
|
|
if( NS_SUCCEEDED(sourceAttributes->Item(i, getter_AddRefs(attrNode))) && attrNode)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMAttr> sourceAttribute = do_QueryInterface(attrNode);
|
|
|
|
if (sourceAttribute)
|
|
|
|
{
|
1999-09-14 23:44:05 +00:00
|
|
|
nsAutoString sourceAttrName;
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_SUCCEEDED(sourceAttribute->GetName(sourceAttrName)))
|
|
|
|
{
|
1999-09-14 23:44:05 +00:00
|
|
|
nsAutoString sourceAttrValue;
|
2000-10-08 06:14:21 +00:00
|
|
|
/*
|
|
|
|
Presence of an attribute in the named node map indicates that it was set on the
|
|
|
|
element even if it has no value.
|
|
|
|
*/
|
|
|
|
if (NS_SUCCEEDED(sourceAttribute->GetValue(sourceAttrValue)))
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
2002-01-09 13:51:37 +00:00
|
|
|
if (destInBody) {
|
2002-09-17 12:04:59 +00:00
|
|
|
result = SetAttributeOrEquivalent(destElement, sourceAttrName, sourceAttrValue, PR_FALSE);
|
2002-01-09 13:51:37 +00:00
|
|
|
}
|
|
|
|
else {
|
2002-09-17 12:04:59 +00:00
|
|
|
// the element is not inserted in the document yet, we don't want to put a
|
|
|
|
// transaction on the UndoStack
|
|
|
|
result = SetAttributeOrEquivalent(destElement, sourceAttrName, sourceAttrValue, PR_TRUE);
|
2002-01-09 13:51:37 +00:00
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
} else {
|
|
|
|
// Do we ever get here?
|
|
|
|
#if DEBUG_cmanske
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("Attribute in sourceAttribute has empty value in nsEditor::CloneAttributes()\n");
|
1999-08-09 01:37:50 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
1999-02-15 18:25:30 +00:00
|
|
|
}
|
|
|
|
}
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
1999-03-02 05:30:53 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
2000-03-24 00:26:47 +00:00
|
|
|
#pragma mark Protected and static methods
|
1999-08-09 01:37:50 +00:00
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
2002-06-13 20:35:12 +00:00
|
|
|
NS_IMETHODIMP nsEditor::ScrollSelectionIntoView(PRBool aScrollToAnchor)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
2002-06-13 20:35:12 +00:00
|
|
|
nsCOMPtr<nsISelectionController> selCon;
|
|
|
|
if (NS_SUCCEEDED(GetSelectionController(getter_AddRefs(selCon))) && selCon)
|
|
|
|
{
|
|
|
|
PRInt16 region = nsISelectionController::SELECTION_FOCUS_REGION;
|
|
|
|
|
|
|
|
if (aScrollToAnchor)
|
|
|
|
region = nsISelectionController::SELECTION_ANCHOR_REGION;
|
|
|
|
|
|
|
|
PRBool syncScroll = PR_TRUE;
|
|
|
|
PRUint32 flags = 0;
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(GetFlags(&flags)))
|
|
|
|
{
|
|
|
|
// If the editor is relying on asynchronous reflows, we have
|
|
|
|
// to use asynchronous requests to scroll, so that the scrolling happens
|
|
|
|
// after reflow requests are processed.
|
2007-08-29 18:57:29 +00:00
|
|
|
// XXXbz why not just always do async scroll?
|
2002-06-13 20:35:12 +00:00
|
|
|
syncScroll = !(flags & nsIPlaintextEditor::eEditorUseAsyncUpdatesMask);
|
|
|
|
}
|
|
|
|
|
2008-02-28 15:28:37 +00:00
|
|
|
// After ScrollSelectionIntoView(), the pending notifications might be
|
|
|
|
// flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
|
2002-06-13 20:35:12 +00:00
|
|
|
selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
|
|
|
|
region, syncScroll);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
|
2002-03-23 22:16:54 +00:00
|
|
|
NS_IMETHODIMP nsEditor::InsertTextImpl(const nsAString& aStringToInsert,
|
2000-03-24 00:26:47 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> *aInOutNode,
|
|
|
|
PRInt32 *aInOutOffset,
|
|
|
|
nsIDOMDocument *aDoc)
|
|
|
|
{
|
|
|
|
// NOTE: caller *must* have already used nsAutoTxnsConserveSelection stack-based
|
|
|
|
// class to turn off txn selection updating. Caller also turned on rules sniffing
|
|
|
|
// if desired.
|
|
|
|
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(aInOutNode && *aInOutNode && aInOutOffset && aDoc, NS_ERROR_NULL_POINTER);
|
2000-04-13 21:50:19 +00:00
|
|
|
if (!mInIMEMode && aStringToInsert.IsEmpty()) return NS_OK;
|
2000-03-24 00:26:47 +00:00
|
|
|
nsCOMPtr<nsIDOMText> nodeAsText = do_QueryInterface(*aInOutNode);
|
|
|
|
PRInt32 offset = *aInOutOffset;
|
|
|
|
nsresult res;
|
2000-03-29 12:53:23 +00:00
|
|
|
if (mInIMEMode)
|
2000-03-24 00:26:47 +00:00
|
|
|
{
|
2000-03-29 12:53:23 +00:00
|
|
|
if (!nodeAsText)
|
|
|
|
{
|
|
|
|
// create a text node
|
2004-01-29 22:04:45 +00:00
|
|
|
res = aDoc->CreateTextNode(EmptyString(), getter_AddRefs(nodeAsText));
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(nodeAsText, NS_ERROR_NULL_POINTER);
|
2003-06-30 17:28:52 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> newNode = do_QueryInterface(nodeAsText);
|
2000-03-29 12:53:23 +00:00
|
|
|
// then we insert it into the dom tree
|
|
|
|
res = InsertNode(newNode, *aInOutNode, offset);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-03-29 12:53:23 +00:00
|
|
|
offset = 0;
|
|
|
|
}
|
2000-04-13 21:50:19 +00:00
|
|
|
res = InsertTextIntoTextNodeImpl(aStringToInsert, nodeAsText, offset);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-03-24 00:26:47 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-03-29 12:53:23 +00:00
|
|
|
if (nodeAsText)
|
|
|
|
{
|
|
|
|
// we are inserting text into an existing text node.
|
2000-04-13 21:50:19 +00:00
|
|
|
res = InsertTextIntoTextNodeImpl(aStringToInsert, nodeAsText, offset);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-03-29 12:53:23 +00:00
|
|
|
*aInOutOffset += aStringToInsert.Length();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// we are inserting text into a non-text node
|
|
|
|
// first we have to create a textnode (this also populates it with the text)
|
|
|
|
res = aDoc->CreateTextNode(aStringToInsert, getter_AddRefs(nodeAsText));
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(nodeAsText, NS_ERROR_NULL_POINTER);
|
2003-06-30 18:55:06 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> newNode = do_QueryInterface(nodeAsText);
|
2000-03-29 12:53:23 +00:00
|
|
|
// then we insert it into the dom tree
|
|
|
|
res = InsertNode(newNode, *aInOutNode, offset);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-03-29 12:53:23 +00:00
|
|
|
*aInOutNode = newNode;
|
|
|
|
*aInOutOffset = aStringToInsert.Length();
|
|
|
|
}
|
2000-03-24 00:26:47 +00:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-13 02:35:50 +00:00
|
|
|
nsresult nsEditor::InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert,
|
|
|
|
nsIDOMCharacterData *aTextNode,
|
|
|
|
PRInt32 aOffset,
|
|
|
|
PRBool aSuppressIME)
|
2000-03-24 00:26:47 +00:00
|
|
|
{
|
2007-07-02 14:01:27 +00:00
|
|
|
nsRefPtr<EditTxn> txn;
|
2008-10-09 23:30:48 +00:00
|
|
|
nsresult result = NS_OK;
|
2010-01-13 02:35:50 +00:00
|
|
|
PRBool isIMETransaction = PR_FALSE;
|
|
|
|
// aSuppressIME is used when editor must insert text, yet this text is not
|
2002-04-06 19:07:47 +00:00
|
|
|
// part of current ime operation. example: adjusting whitespace around an ime insertion.
|
2010-01-13 02:35:50 +00:00
|
|
|
if (mIMETextRangeList && mInIMEMode && !aSuppressIME)
|
2000-03-29 12:53:23 +00:00
|
|
|
{
|
|
|
|
if (!mIMETextNode)
|
|
|
|
{
|
|
|
|
mIMETextNode = aTextNode;
|
|
|
|
mIMETextOffset = aOffset;
|
|
|
|
}
|
2002-12-17 23:38:04 +00:00
|
|
|
PRUint16 len ;
|
2008-10-09 23:30:48 +00:00
|
|
|
len = mIMETextRangeList->GetLength();
|
|
|
|
if (len > 0)
|
2002-12-17 23:38:04 +00:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIPrivateTextRange> range;
|
|
|
|
for (PRUint16 i = 0; i < len; i++)
|
|
|
|
{
|
2008-10-09 23:30:48 +00:00
|
|
|
range = mIMETextRangeList->Item(i);
|
|
|
|
if (range)
|
2002-12-17 23:38:04 +00:00
|
|
|
{
|
|
|
|
PRUint16 type;
|
|
|
|
result = range->GetRangeType(&type);
|
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{
|
|
|
|
if (type == nsIPrivateTextRange::TEXTRANGE_RAWINPUT)
|
|
|
|
{
|
|
|
|
PRUint16 start, end;
|
|
|
|
result = range->GetRangeStart(&start);
|
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{
|
|
|
|
result = range->GetRangeEnd(&end);
|
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{
|
|
|
|
if (!mPhonetic)
|
|
|
|
mPhonetic = new nsString();
|
|
|
|
if (mPhonetic)
|
|
|
|
{
|
|
|
|
nsAutoString tmp(aStringToInsert);
|
|
|
|
tmp.Mid(*mPhonetic, start, end-start);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // if
|
|
|
|
}
|
|
|
|
} // if
|
|
|
|
} // for
|
|
|
|
} // if
|
|
|
|
|
2007-07-02 14:01:27 +00:00
|
|
|
nsRefPtr<IMETextTxn> imeTxn;
|
|
|
|
result = CreateTxnForIMEText(aStringToInsert, getter_AddRefs(imeTxn));
|
|
|
|
txn = imeTxn;
|
2010-01-13 02:35:50 +00:00
|
|
|
isIMETransaction = PR_TRUE;
|
2000-03-29 12:53:23 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-07-02 14:01:27 +00:00
|
|
|
nsRefPtr<InsertTextTxn> insertTxn;
|
|
|
|
result = CreateTxnForInsertText(aStringToInsert, aTextNode, aOffset,
|
|
|
|
getter_AddRefs(insertTxn));
|
|
|
|
txn = insertTxn;
|
2000-03-29 12:53:23 +00:00
|
|
|
}
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2000-03-24 00:26:47 +00:00
|
|
|
|
2005-11-25 08:16:51 +00:00
|
|
|
// let listeners know what's up
|
2000-03-24 00:26:47 +00:00
|
|
|
PRInt32 i;
|
2006-10-09 15:41:26 +00:00
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->WillInsertText(aTextNode, aOffset, aStringToInsert);
|
2002-04-13 23:54:59 +00:00
|
|
|
|
|
|
|
// XXX we may not need these view batches anymore. This is handled at a higher level now I believe
|
2000-03-24 00:26:47 +00:00
|
|
|
BeginUpdateViewBatch();
|
2003-04-04 20:50:25 +00:00
|
|
|
result = DoTransaction(txn);
|
2000-03-24 00:26:47 +00:00
|
|
|
EndUpdateViewBatch();
|
|
|
|
|
2002-04-13 23:54:59 +00:00
|
|
|
mRangeUpdater.SelAdjInsertText(aTextNode, aOffset, aStringToInsert);
|
|
|
|
|
2000-03-24 00:26:47 +00:00
|
|
|
// let listeners know what happened
|
2006-10-09 15:41:26 +00:00
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->DidInsertText(aTextNode, aOffset, aStringToInsert, result);
|
2000-03-24 00:26:47 +00:00
|
|
|
|
2000-07-11 19:51:36 +00:00
|
|
|
// Added some cruft here for bug 43366. Layout was crashing because we left an
|
|
|
|
// empty text node lying around in the document. So I delete empty text nodes
|
|
|
|
// caused by IME. I have to mark the IME transaction as "fixed", which means
|
|
|
|
// that furure ime txns won't merge with it. This is because we don't want
|
|
|
|
// future ime txns trying to put their text into a node that is no longer in
|
|
|
|
// the document. This does not break undo/redo, because all these txns are
|
|
|
|
// wrapped in a parent PlaceHolder txn, and placeholder txns are already
|
|
|
|
// savvy to having multiple ime txns inside them.
|
|
|
|
|
|
|
|
// delete empty ime text node if there is one
|
2010-01-13 02:35:50 +00:00
|
|
|
if (isIMETransaction)
|
2000-07-11 19:51:36 +00:00
|
|
|
{
|
|
|
|
PRUint32 len;
|
|
|
|
mIMETextNode->GetLength(&len);
|
|
|
|
if (!len)
|
|
|
|
{
|
|
|
|
DeleteNode(mIMETextNode);
|
|
|
|
mIMETextNode = nsnull;
|
2007-07-08 07:08:04 +00:00
|
|
|
static_cast<IMETextTxn*>(txn.get())->MarkFixed(); // mark the ime txn "fixed"
|
2000-07-11 19:51:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-03-24 00:26:47 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-09-14 11:45:01 +00:00
|
|
|
NS_IMETHODIMP nsEditor::SelectEntireDocument(nsISelection *aSelection)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
if (!aSelection) { return NS_ERROR_NULL_POINTER; }
|
2005-03-24 19:00:01 +00:00
|
|
|
|
|
|
|
nsIDOMElement *rootElement = GetRoot();
|
|
|
|
if (!rootElement) { return NS_ERROR_NOT_INITIALIZED; }
|
|
|
|
|
|
|
|
return aSelection->SelectAllChildren(rootElement);
|
1999-03-10 19:48:13 +00:00
|
|
|
}
|
|
|
|
|
1999-09-22 01:23:58 +00:00
|
|
|
|
1999-11-17 11:03:25 +00:00
|
|
|
nsresult nsEditor::GetFirstEditableNode(nsIDOMNode *aRoot, nsCOMPtr<nsIDOMNode> *outFirstNode)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(aRoot && outFirstNode, NS_ERROR_NULL_POINTER);
|
2001-08-22 05:32:44 +00:00
|
|
|
nsresult rv = NS_OK;
|
1999-09-22 01:23:58 +00:00
|
|
|
*outFirstNode = nsnull;
|
1999-11-17 11:03:25 +00:00
|
|
|
|
2003-06-30 17:28:52 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> node = GetLeftmostChild(aRoot);
|
1999-11-17 11:03:25 +00:00
|
|
|
if (node && !IsEditable(node))
|
1999-09-22 01:23:58 +00:00
|
|
|
{
|
2003-06-30 17:28:52 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> next;
|
2001-08-22 05:32:44 +00:00
|
|
|
rv = GetNextNode(node, PR_TRUE, address_of(next));
|
1999-11-17 11:03:25 +00:00
|
|
|
node = next;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
1999-09-22 01:23:58 +00:00
|
|
|
|
2003-06-30 17:28:52 +00:00
|
|
|
if (node != aRoot)
|
|
|
|
*outFirstNode = node;
|
1999-11-17 11:03:25 +00:00
|
|
|
|
|
|
|
return rv;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
|
2002-01-14 20:25:17 +00:00
|
|
|
#ifdef XXX_DEAD_CODE
|
|
|
|
// jfrancis wants to keep this method around for reference
|
1999-11-17 11:03:25 +00:00
|
|
|
nsresult nsEditor::GetLastEditableNode(nsIDOMNode *aRoot, nsCOMPtr<nsIDOMNode> *outLastNode)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(aRoot && outLastNode, NS_ERROR_NULL_POINTER);
|
2001-08-22 05:32:44 +00:00
|
|
|
nsresult rv = NS_OK;
|
1999-09-22 01:23:58 +00:00
|
|
|
*outLastNode = nsnull;
|
1999-11-17 11:03:25 +00:00
|
|
|
|
2003-06-30 17:28:52 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> node = GetRightmostChild(aRoot);
|
1999-11-17 11:03:25 +00:00
|
|
|
if (node && !IsEditable(node))
|
1999-09-22 01:23:58 +00:00
|
|
|
{
|
2003-06-30 17:28:52 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> next;
|
2001-08-22 05:32:44 +00:00
|
|
|
rv = GetPriorNode(node, PR_TRUE, address_of(next));
|
1999-11-17 11:03:25 +00:00
|
|
|
node = next;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
2003-06-30 17:28:52 +00:00
|
|
|
|
|
|
|
if (node != aRoot)
|
|
|
|
*outLastNode = node;
|
1999-11-17 11:03:25 +00:00
|
|
|
|
|
|
|
return rv;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
2002-01-14 20:25:17 +00:00
|
|
|
#endif
|
1999-08-09 01:37:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::NotifyDocumentListeners(TDocumentListenerNotification aNotificationType)
|
|
|
|
{
|
2006-10-09 15:41:26 +00:00
|
|
|
PRInt32 numListeners = mDocStateListeners.Count();
|
2010-06-21 15:02:14 +00:00
|
|
|
if (!numListeners) // maybe there just aren't any.
|
|
|
|
return NS_OK;
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2009-07-08 18:38:13 +00:00
|
|
|
nsCOMArray<nsIDocumentStateListener> listeners(mDocStateListeners);
|
2006-10-09 15:41:26 +00:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
PRInt32 i;
|
2009-07-08 18:38:13 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
switch (aNotificationType)
|
|
|
|
{
|
|
|
|
case eDocumentCreated:
|
|
|
|
for (i = 0; i < numListeners;i++)
|
|
|
|
{
|
2009-07-08 18:38:13 +00:00
|
|
|
rv = listeners[i]->NotifyDocumentCreated();
|
2006-10-09 15:41:26 +00:00
|
|
|
if (NS_FAILED(rv))
|
|
|
|
break;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case eDocumentToBeDestroyed:
|
|
|
|
for (i = 0; i < numListeners;i++)
|
|
|
|
{
|
2009-07-08 18:38:13 +00:00
|
|
|
rv = listeners[i]->NotifyDocumentWillBeDestroyed();
|
2006-10-09 15:41:26 +00:00
|
|
|
if (NS_FAILED(rv))
|
|
|
|
break;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case eDocumentStateChanged:
|
|
|
|
{
|
|
|
|
PRBool docIsDirty;
|
|
|
|
rv = GetDocumentModified(&docIsDirty);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
1999-08-09 01:37:50 +00:00
|
|
|
|
|
|
|
if (docIsDirty == mDocDirtyState)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
mDocDirtyState = (PRInt8)docIsDirty;
|
|
|
|
|
|
|
|
for (i = 0; i < numListeners;i++)
|
|
|
|
{
|
2009-07-08 18:38:13 +00:00
|
|
|
rv = listeners[i]->NotifyDocumentStateChanged(mDocDirtyState);
|
2006-10-09 15:41:26 +00:00
|
|
|
if (NS_FAILED(rv))
|
|
|
|
break;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
NS_NOTREACHED("Unknown notification");
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-03-23 22:16:54 +00:00
|
|
|
NS_IMETHODIMP nsEditor::CreateTxnForInsertText(const nsAString & aStringToInsert,
|
1999-08-09 01:37:50 +00:00
|
|
|
nsIDOMCharacterData *aTextNode,
|
1999-10-26 18:54:47 +00:00
|
|
|
PRInt32 aOffset,
|
1999-08-09 01:37:50 +00:00
|
|
|
InsertTextTxn ** aTxn)
|
|
|
|
{
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(aTextNode && aTxn, NS_ERROR_NULL_POINTER);
|
1999-08-09 01:37:50 +00:00
|
|
|
nsresult result;
|
|
|
|
|
2009-04-24 22:45:34 +00:00
|
|
|
*aTxn = new InsertTextTxn();
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(*aTxn, NS_ERROR_OUT_OF_MEMORY);
|
2009-04-24 22:45:34 +00:00
|
|
|
NS_ADDREF(*aTxn);
|
2000-01-04 03:09:41 +00:00
|
|
|
result = (*aTxn)->Init(aTextNode, aOffset, aStringToInsert, this);
|
1999-08-09 01:37:50 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2000-01-04 03:09:41 +00:00
|
|
|
|
1999-03-02 05:30:53 +00:00
|
|
|
NS_IMETHODIMP nsEditor::DeleteText(nsIDOMCharacterData *aElement,
|
1999-02-12 17:18:58 +00:00
|
|
|
PRUint32 aOffset,
|
|
|
|
PRUint32 aLength)
|
|
|
|
{
|
2007-07-02 14:01:27 +00:00
|
|
|
nsRefPtr<DeleteTextTxn> txn;
|
|
|
|
nsresult result = CreateTxnForDeleteText(aElement, aOffset, aLength,
|
|
|
|
getter_AddRefs(txn));
|
1999-12-07 08:30:19 +00:00
|
|
|
nsAutoRules beginRulesSniffing(this, kOpDeleteText, nsIEditor::ePrevious);
|
1999-11-25 00:16:56 +00:00
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{
|
2005-11-25 08:16:51 +00:00
|
|
|
// let listeners know what's up
|
1999-11-25 00:16:56 +00:00
|
|
|
PRInt32 i;
|
2006-10-09 15:41:26 +00:00
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->WillDeleteText(aElement, aOffset, aLength);
|
1999-11-25 00:16:56 +00:00
|
|
|
|
2003-04-04 20:50:25 +00:00
|
|
|
result = DoTransaction(txn);
|
1999-11-25 00:16:56 +00:00
|
|
|
|
2000-01-04 03:09:41 +00:00
|
|
|
// let listeners know what happened
|
2006-10-09 15:41:26 +00:00
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->DidDeleteText(aElement, aOffset, aLength, result);
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-03-02 05:30:53 +00:00
|
|
|
NS_IMETHODIMP nsEditor::CreateTxnForDeleteText(nsIDOMCharacterData *aElement,
|
1999-03-10 19:48:13 +00:00
|
|
|
PRUint32 aOffset,
|
|
|
|
PRUint32 aLength,
|
|
|
|
DeleteTextTxn **aTxn)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
|
2003-06-30 17:28:52 +00:00
|
|
|
|
2009-04-24 22:45:34 +00:00
|
|
|
*aTxn = new DeleteTextTxn();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(*aTxn, NS_ERROR_OUT_OF_MEMORY);
|
2009-04-24 22:45:34 +00:00
|
|
|
NS_ADDREF(*aTxn);
|
|
|
|
return (*aTxn)->Init(this, aElement, aOffset, aLength, &mRangeUpdater);
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-04-08 00:46:10 +00:00
|
|
|
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_IMETHODIMP nsEditor::CreateTxnForSplitNode(nsIDOMNode *aNode,
|
|
|
|
PRUint32 aOffset,
|
|
|
|
SplitElementTxn **aTxn)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
|
2003-06-30 17:28:52 +00:00
|
|
|
|
2009-04-24 22:45:34 +00:00
|
|
|
*aTxn = new SplitElementTxn();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(*aTxn, NS_ERROR_OUT_OF_MEMORY);
|
2009-04-24 22:45:34 +00:00
|
|
|
NS_ADDREF(*aTxn);
|
2003-06-30 17:28:52 +00:00
|
|
|
|
|
|
|
return (*aTxn)->Init(this, aNode, aOffset);
|
1999-04-08 00:46:10 +00:00
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_IMETHODIMP nsEditor::CreateTxnForJoinNode(nsIDOMNode *aLeftNode,
|
|
|
|
nsIDOMNode *aRightNode,
|
|
|
|
JoinElementTxn **aTxn)
|
1999-03-02 05:30:53 +00:00
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aLeftNode && aRightNode, NS_ERROR_NULL_POINTER);
|
2003-06-30 18:55:06 +00:00
|
|
|
|
2009-04-24 22:45:34 +00:00
|
|
|
*aTxn = new JoinElementTxn();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(*aTxn, NS_ERROR_OUT_OF_MEMORY);
|
2009-04-24 22:45:34 +00:00
|
|
|
NS_ADDREF(*aTxn);
|
|
|
|
|
|
|
|
return (*aTxn)->Init(this, aLeftNode, aRightNode);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// END nsEditor core implementation
|
|
|
|
|
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
2000-03-24 00:26:47 +00:00
|
|
|
#pragma mark nsEditor public static helper methods
|
1999-08-09 01:37:50 +00:00
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
2000-01-04 03:09:41 +00:00
|
|
|
// BEGIN nsEditor public helper methods
|
1999-08-09 01:37:50 +00:00
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode,
|
|
|
|
PRInt32 aOffset,
|
|
|
|
nsIDOMNode* aNewLeftNode,
|
|
|
|
nsIDOMNode* aParent)
|
|
|
|
{
|
2003-05-23 21:43:10 +00:00
|
|
|
#ifdef NS_DEBUG_EDITOR
|
2001-01-25 23:12:16 +00:00
|
|
|
if (gNoisy) { printf("SplitNodeImpl: left=%p, right=%p, offset=%d\n", (void*)aNewLeftNode, (void*)aExistingRightNode, aOffset); }
|
2003-05-23 21:43:10 +00:00
|
|
|
#endif
|
2003-06-30 18:55:06 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_ASSERTION(((nsnull!=aExistingRightNode) &&
|
|
|
|
(nsnull!=aNewLeftNode) &&
|
|
|
|
(nsnull!=aParent)),
|
|
|
|
"null arg");
|
2003-06-30 18:55:06 +00:00
|
|
|
nsresult result;
|
1999-08-09 01:37:50 +00:00
|
|
|
if ((nsnull!=aExistingRightNode) &&
|
|
|
|
(nsnull!=aNewLeftNode) &&
|
|
|
|
(nsnull!=aParent))
|
|
|
|
{
|
2000-01-04 03:09:41 +00:00
|
|
|
// get selection
|
2000-09-14 11:45:01 +00:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
2000-01-06 22:35:04 +00:00
|
|
|
result = GetSelection(getter_AddRefs(selection));
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
|
2000-01-04 03:09:41 +00:00
|
|
|
|
|
|
|
// remember some selection points
|
|
|
|
nsCOMPtr<nsIDOMNode> selStartNode, selEndNode;
|
|
|
|
PRInt32 selStartOffset, selEndOffset;
|
2010-06-11 02:46:51 +00:00
|
|
|
result = GetStartNodeAndOffset(selection, getter_AddRefs(selStartNode), &selStartOffset);
|
2000-03-24 00:26:47 +00:00
|
|
|
if (NS_FAILED(result)) selStartNode = nsnull; // if selection is cleared, remember that
|
2010-06-11 02:46:51 +00:00
|
|
|
result = GetEndNodeAndOffset(selection, getter_AddRefs(selEndNode), &selEndOffset);
|
2000-03-24 00:26:47 +00:00
|
|
|
if (NS_FAILED(result)) selStartNode = nsnull; // if selection is cleared, remember that
|
2000-01-04 03:09:41 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> resultNode;
|
|
|
|
result = aParent->InsertBefore(aNewLeftNode, aExistingRightNode, getter_AddRefs(resultNode));
|
2000-10-28 22:17:53 +00:00
|
|
|
//printf(" after insert\n"); content->List(); // DEBUG
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_SUCCEEDED(result))
|
1999-03-02 05:30:53 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
// split the children between the 2 nodes
|
|
|
|
// at this point, aExistingRightNode has all the children
|
|
|
|
// move all the children whose index is < aOffset to aNewLeftNode
|
|
|
|
if (0<=aOffset) // don't bother unless we're going to move at least one child
|
|
|
|
{
|
|
|
|
// if it's a text node, just shuffle around some text
|
|
|
|
nsCOMPtr<nsIDOMCharacterData> rightNodeAsText( do_QueryInterface(aExistingRightNode) );
|
|
|
|
nsCOMPtr<nsIDOMCharacterData> leftNodeAsText( do_QueryInterface(aNewLeftNode) );
|
|
|
|
if (leftNodeAsText && rightNodeAsText)
|
1999-03-17 06:13:46 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
// fix right node
|
1999-09-14 23:44:05 +00:00
|
|
|
nsAutoString leftText;
|
1999-08-09 01:37:50 +00:00
|
|
|
rightNodeAsText->SubstringData(0, aOffset, leftText);
|
|
|
|
rightNodeAsText->DeleteData(0, aOffset);
|
|
|
|
// fix left node
|
|
|
|
leftNodeAsText->SetData(leftText);
|
|
|
|
// moose
|
1999-03-17 06:13:46 +00:00
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
else
|
|
|
|
{ // otherwise it's an interior node, so shuffle around the children
|
|
|
|
// go through list backwards so deletes don't interfere with the iteration
|
|
|
|
nsCOMPtr<nsIDOMNodeList> childNodes;
|
|
|
|
result = aExistingRightNode->GetChildNodes(getter_AddRefs(childNodes));
|
|
|
|
if ((NS_SUCCEEDED(result)) && (childNodes))
|
1999-03-02 05:30:53 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
PRInt32 i=aOffset-1;
|
|
|
|
for ( ; ((NS_SUCCEEDED(result)) && (0<=i)); i--)
|
1999-07-14 15:24:33 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> childNode;
|
|
|
|
result = childNodes->Item(i, getter_AddRefs(childNode));
|
|
|
|
if ((NS_SUCCEEDED(result)) && (childNode))
|
1999-07-14 15:24:33 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
result = aExistingRightNode->RemoveChild(childNode, getter_AddRefs(resultNode));
|
2000-10-28 22:17:53 +00:00
|
|
|
//printf(" after remove\n"); content->List(); // DEBUG
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> firstChild;
|
|
|
|
aNewLeftNode->GetFirstChild(getter_AddRefs(firstChild));
|
|
|
|
result = aNewLeftNode->InsertBefore(childNode, firstChild, getter_AddRefs(resultNode));
|
2000-10-28 22:17:53 +00:00
|
|
|
//printf(" after append\n"); content->List(); // DEBUG
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
1999-03-10 19:48:13 +00:00
|
|
|
}
|
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
1999-03-02 05:30:53 +00:00
|
|
|
}
|
2000-01-04 03:09:41 +00:00
|
|
|
// handle selection
|
2010-05-18 08:58:38 +00:00
|
|
|
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
|
|
|
if (ps)
|
|
|
|
ps->FlushPendingNotifications(Flush_Frames);
|
|
|
|
|
2000-01-04 03:09:41 +00:00
|
|
|
if (GetShouldTxnSetSelection())
|
|
|
|
{
|
|
|
|
// editor wants us to set selection at split point
|
|
|
|
selection->Collapse(aNewLeftNode, aOffset);
|
|
|
|
}
|
2000-03-24 00:26:47 +00:00
|
|
|
else if (selStartNode)
|
2000-01-04 03:09:41 +00:00
|
|
|
{
|
2000-03-24 00:26:47 +00:00
|
|
|
// else adjust the selection if needed. if selStartNode is null, then there was no selection.
|
2000-01-04 03:09:41 +00:00
|
|
|
// HACK: this is overly simplified - multi-range selections need more work than this
|
2000-01-04 04:28:39 +00:00
|
|
|
if (selStartNode.get() == aExistingRightNode)
|
2000-01-04 03:09:41 +00:00
|
|
|
{
|
|
|
|
if (selStartOffset < aOffset)
|
|
|
|
{
|
|
|
|
selStartNode = aNewLeftNode;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
selStartOffset -= aOffset;
|
|
|
|
}
|
|
|
|
}
|
2000-01-04 04:28:39 +00:00
|
|
|
if (selEndNode.get() == aExistingRightNode)
|
2000-01-04 03:09:41 +00:00
|
|
|
{
|
|
|
|
if (selEndOffset < aOffset)
|
|
|
|
{
|
|
|
|
selEndNode = aNewLeftNode;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
selEndOffset -= aOffset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
selection->Collapse(selStartNode,selStartOffset);
|
|
|
|
selection->Extend(selEndNode,selEndOffset);
|
|
|
|
}
|
1999-03-02 05:30:53 +00:00
|
|
|
}
|
1999-03-17 06:13:46 +00:00
|
|
|
}
|
1999-03-02 05:30:53 +00:00
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
else
|
|
|
|
result = NS_ERROR_INVALID_ARG;
|
1999-02-12 17:18:58 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
nsresult
|
|
|
|
nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep,
|
|
|
|
nsIDOMNode * aNodeToJoin,
|
|
|
|
nsIDOMNode * aParent,
|
|
|
|
PRBool aNodeToKeepIsFirst)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
2000-01-04 03:09:41 +00:00
|
|
|
NS_ASSERTION(aNodeToKeep && aNodeToJoin && aParent, "null arg");
|
2003-06-30 18:55:06 +00:00
|
|
|
nsresult result;
|
2000-01-04 03:09:41 +00:00
|
|
|
if (aNodeToKeep && aNodeToJoin && aParent)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
2000-01-04 03:09:41 +00:00
|
|
|
// get selection
|
2000-09-14 11:45:01 +00:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
2000-01-04 03:09:41 +00:00
|
|
|
GetSelection(getter_AddRefs(selection));
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
|
2000-01-04 03:09:41 +00:00
|
|
|
|
|
|
|
// remember some selection points
|
2003-06-30 18:55:06 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> selStartNode, selEndNode;
|
2000-01-05 12:24:10 +00:00
|
|
|
PRInt32 selStartOffset, selEndOffset, joinOffset, keepOffset;
|
2010-06-11 02:46:51 +00:00
|
|
|
result = GetStartNodeAndOffset(selection, getter_AddRefs(selStartNode), &selStartOffset);
|
2000-03-24 00:26:47 +00:00
|
|
|
if (NS_FAILED(result)) selStartNode = nsnull;
|
2010-06-11 02:46:51 +00:00
|
|
|
result = GetEndNodeAndOffset(selection, getter_AddRefs(selEndNode), &selEndOffset);
|
2003-06-30 18:55:06 +00:00
|
|
|
// Joe or Kin should comment here on why the following line is not a copy/paste error
|
2000-03-24 00:26:47 +00:00
|
|
|
if (NS_FAILED(result)) selStartNode = nsnull;
|
2003-06-30 18:55:06 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> leftNode;
|
|
|
|
if (aNodeToKeepIsFirst)
|
|
|
|
leftNode = aNodeToKeep;
|
|
|
|
else
|
|
|
|
leftNode = aNodeToJoin;
|
|
|
|
|
2000-01-04 03:09:41 +00:00
|
|
|
PRUint32 firstNodeLength;
|
|
|
|
result = GetLengthOfDOMNode(leftNode, firstNodeLength);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2003-06-30 18:55:06 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
2000-12-09 04:46:08 +00:00
|
|
|
result = GetNodeLocation(aNodeToJoin, address_of(parent), &joinOffset);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2000-12-09 04:46:08 +00:00
|
|
|
result = GetNodeLocation(aNodeToKeep, address_of(parent), &keepOffset);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2000-01-04 03:09:41 +00:00
|
|
|
|
2000-01-05 12:24:10 +00:00
|
|
|
// if selection endpoint is between the nodes, remember it as being
|
|
|
|
// in the one that is going away instead. This simplifies later selection
|
|
|
|
// adjustment logic at end of this method.
|
2000-03-24 00:26:47 +00:00
|
|
|
if (selStartNode)
|
2000-01-05 12:24:10 +00:00
|
|
|
{
|
2000-03-24 00:26:47 +00:00
|
|
|
if (selStartNode == parent)
|
2000-01-05 12:24:10 +00:00
|
|
|
{
|
2000-03-24 00:26:47 +00:00
|
|
|
if (aNodeToKeepIsFirst)
|
2000-01-05 12:24:10 +00:00
|
|
|
{
|
2000-03-24 00:26:47 +00:00
|
|
|
if ((selStartOffset > keepOffset) && (selStartOffset <= joinOffset))
|
|
|
|
{
|
|
|
|
selStartNode = aNodeToJoin;
|
|
|
|
selStartOffset = 0;
|
|
|
|
}
|
2000-01-05 12:24:10 +00:00
|
|
|
}
|
2000-03-24 00:26:47 +00:00
|
|
|
else
|
2000-01-05 12:24:10 +00:00
|
|
|
{
|
2000-03-24 00:26:47 +00:00
|
|
|
if ((selStartOffset > joinOffset) && (selStartOffset <= keepOffset))
|
|
|
|
{
|
|
|
|
selStartNode = aNodeToJoin;
|
|
|
|
selStartOffset = firstNodeLength;
|
|
|
|
}
|
2000-01-05 12:24:10 +00:00
|
|
|
}
|
|
|
|
}
|
2000-03-24 00:26:47 +00:00
|
|
|
if (selEndNode == parent)
|
2000-01-05 12:24:10 +00:00
|
|
|
{
|
2000-03-24 00:26:47 +00:00
|
|
|
if (aNodeToKeepIsFirst)
|
2000-01-05 12:24:10 +00:00
|
|
|
{
|
2000-03-24 00:26:47 +00:00
|
|
|
if ((selEndOffset > keepOffset) && (selEndOffset <= joinOffset))
|
|
|
|
{
|
|
|
|
selEndNode = aNodeToJoin;
|
|
|
|
selEndOffset = 0;
|
|
|
|
}
|
2000-01-05 12:24:10 +00:00
|
|
|
}
|
2000-03-24 00:26:47 +00:00
|
|
|
else
|
2000-01-05 12:24:10 +00:00
|
|
|
{
|
2000-03-24 00:26:47 +00:00
|
|
|
if ((selEndOffset > joinOffset) && (selEndOffset <= keepOffset))
|
|
|
|
{
|
|
|
|
selEndNode = aNodeToJoin;
|
|
|
|
selEndOffset = firstNodeLength;
|
|
|
|
}
|
2000-01-05 12:24:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// ok, ready to do join now.
|
1999-08-09 01:37:50 +00:00
|
|
|
// if it's a text node, just shuffle around some text
|
|
|
|
nsCOMPtr<nsIDOMCharacterData> keepNodeAsText( do_QueryInterface(aNodeToKeep) );
|
|
|
|
nsCOMPtr<nsIDOMCharacterData> joinNodeAsText( do_QueryInterface(aNodeToJoin) );
|
|
|
|
if (keepNodeAsText && joinNodeAsText)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
1999-09-14 23:44:05 +00:00
|
|
|
nsAutoString rightText;
|
|
|
|
nsAutoString leftText;
|
1999-08-09 01:37:50 +00:00
|
|
|
if (aNodeToKeepIsFirst)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
keepNodeAsText->GetData(leftText);
|
|
|
|
joinNodeAsText->GetData(rightText);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
keepNodeAsText->GetData(rightText);
|
|
|
|
joinNodeAsText->GetData(leftText);
|
|
|
|
}
|
|
|
|
leftText += rightText;
|
|
|
|
keepNodeAsText->SetData(leftText);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // otherwise it's an interior node, so shuffle around the children
|
|
|
|
nsCOMPtr<nsIDOMNodeList> childNodes;
|
|
|
|
result = aNodeToJoin->GetChildNodes(getter_AddRefs(childNodes));
|
|
|
|
if ((NS_SUCCEEDED(result)) && (childNodes))
|
|
|
|
{
|
|
|
|
PRInt32 i; // must be signed int!
|
|
|
|
PRUint32 childCount=0;
|
|
|
|
nsCOMPtr<nsIDOMNode> firstNode; //only used if aNodeToKeepIsFirst is false
|
2000-01-04 03:09:41 +00:00
|
|
|
childNodes->GetLength(&childCount);
|
|
|
|
if (!aNodeToKeepIsFirst)
|
1999-08-09 01:37:50 +00:00
|
|
|
{ // remember the first child in aNodeToKeep, we'll insert all the children of aNodeToJoin in front of it
|
|
|
|
result = aNodeToKeep->GetFirstChild(getter_AddRefs(firstNode));
|
|
|
|
// GetFirstChild returns nsnull firstNode if aNodeToKeep has no children, that's ok.
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIDOMNode> resultNode;
|
|
|
|
// have to go through the list backwards to keep deletes from interfering with iteration
|
|
|
|
nsCOMPtr<nsIDOMNode> previousChild;
|
|
|
|
for (i=childCount-1; ((NS_SUCCEEDED(result)) && (0<=i)); i--)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> childNode;
|
|
|
|
result = childNodes->Item(i, getter_AddRefs(childNode));
|
|
|
|
if ((NS_SUCCEEDED(result)) && (childNode))
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
2000-01-04 03:09:41 +00:00
|
|
|
if (aNodeToKeepIsFirst)
|
1999-08-09 01:37:50 +00:00
|
|
|
{ // append children of aNodeToJoin
|
|
|
|
//was result = aNodeToKeep->AppendChild(childNode, getter_AddRefs(resultNode));
|
|
|
|
result = aNodeToKeep->InsertBefore(childNode, previousChild, getter_AddRefs(resultNode));
|
|
|
|
previousChild = do_QueryInterface(childNode);
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
else
|
1999-08-09 01:37:50 +00:00
|
|
|
{ // prepend children of aNodeToJoin
|
|
|
|
result = aNodeToKeep->InsertBefore(childNode, firstNode, getter_AddRefs(resultNode));
|
|
|
|
firstNode = do_QueryInterface(childNode);
|
|
|
|
}
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
else if (!childNodes) {
|
|
|
|
result = NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{ // delete the extra node
|
|
|
|
nsCOMPtr<nsIDOMNode> resultNode;
|
|
|
|
result = aParent->RemoveChild(aNodeToJoin, getter_AddRefs(resultNode));
|
2000-01-04 03:09:41 +00:00
|
|
|
|
|
|
|
if (GetShouldTxnSetSelection())
|
|
|
|
{
|
|
|
|
// editor wants us to set selection at join point
|
|
|
|
selection->Collapse(aNodeToKeep, firstNodeLength);
|
|
|
|
}
|
2000-03-24 00:26:47 +00:00
|
|
|
else if (selStartNode)
|
2000-01-04 03:09:41 +00:00
|
|
|
{
|
|
|
|
// and adjust the selection if needed
|
|
|
|
// HACK: this is overly simplified - multi-range selections need more work than this
|
2000-05-05 20:42:36 +00:00
|
|
|
PRBool bNeedToAdjust = PR_FALSE;
|
2001-03-06 20:16:38 +00:00
|
|
|
|
|
|
|
// check to see if we joined nodes where selection starts
|
2000-01-04 04:28:39 +00:00
|
|
|
if (selStartNode.get() == aNodeToJoin)
|
2000-01-04 03:09:41 +00:00
|
|
|
{
|
2000-05-05 20:42:36 +00:00
|
|
|
bNeedToAdjust = PR_TRUE;
|
2000-01-04 03:09:41 +00:00
|
|
|
selStartNode = aNodeToKeep;
|
|
|
|
if (aNodeToKeepIsFirst)
|
|
|
|
{
|
|
|
|
selStartOffset += firstNodeLength;
|
|
|
|
}
|
|
|
|
}
|
2000-01-05 12:24:10 +00:00
|
|
|
else if ((selStartNode.get() == aNodeToKeep) && !aNodeToKeepIsFirst)
|
|
|
|
{
|
2000-05-05 20:42:36 +00:00
|
|
|
bNeedToAdjust = PR_TRUE;
|
2000-01-05 12:24:10 +00:00
|
|
|
selStartOffset += firstNodeLength;
|
|
|
|
}
|
2001-03-06 20:16:38 +00:00
|
|
|
|
|
|
|
// check to see if we joined nodes where selection ends
|
2000-01-04 04:28:39 +00:00
|
|
|
if (selEndNode.get() == aNodeToJoin)
|
2000-01-04 03:09:41 +00:00
|
|
|
{
|
2000-05-05 20:42:36 +00:00
|
|
|
bNeedToAdjust = PR_TRUE;
|
2000-01-04 03:09:41 +00:00
|
|
|
selEndNode = aNodeToKeep;
|
|
|
|
if (aNodeToKeepIsFirst)
|
|
|
|
{
|
|
|
|
selEndOffset += firstNodeLength;
|
|
|
|
}
|
|
|
|
}
|
2000-01-05 12:24:10 +00:00
|
|
|
else if ((selEndNode.get() == aNodeToKeep) && !aNodeToKeepIsFirst)
|
|
|
|
{
|
2000-05-05 20:42:36 +00:00
|
|
|
bNeedToAdjust = PR_TRUE;
|
2000-01-05 12:24:10 +00:00
|
|
|
selEndOffset += firstNodeLength;
|
|
|
|
}
|
2000-05-05 20:42:36 +00:00
|
|
|
|
2001-03-06 20:16:38 +00:00
|
|
|
// adjust selection if needed
|
2000-05-05 20:42:36 +00:00
|
|
|
if (bNeedToAdjust)
|
2001-03-06 20:16:38 +00:00
|
|
|
{
|
|
|
|
selection->Collapse(selStartNode,selStartOffset);
|
|
|
|
selection->Extend(selEndNode,selEndOffset);
|
|
|
|
}
|
2000-01-04 03:09:41 +00:00
|
|
|
}
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
else
|
|
|
|
result = NS_ERROR_INVALID_ARG;
|
1999-02-12 17:18:58 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
nsresult
|
|
|
|
nsEditor::GetChildOffset(nsIDOMNode *aChild, nsIDOMNode *aParent, PRInt32 &aOffset)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_ASSERTION((aChild && aParent), "bad args");
|
2003-09-27 04:18:26 +00:00
|
|
|
|
2000-03-24 00:26:47 +00:00
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aParent);
|
|
|
|
nsCOMPtr<nsIContent> cChild = do_QueryInterface(aChild);
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(cChild && content, NS_ERROR_NULL_POINTER);
|
2003-09-27 04:18:26 +00:00
|
|
|
|
|
|
|
aOffset = content->IndexOf(cChild);
|
|
|
|
|
|
|
|
return NS_OK;
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
nsresult
|
|
|
|
nsEditor::GetNodeLocation(nsIDOMNode *inChild, nsCOMPtr<nsIDOMNode> *outParent, PRInt32 *outOffset)
|
1999-02-17 19:42:29 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_ASSERTION((inChild && outParent && outOffset), "bad args");
|
|
|
|
nsresult result = NS_ERROR_NULL_POINTER;
|
|
|
|
if (inChild && outParent && outOffset)
|
1999-04-27 17:14:28 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
result = inChild->GetParentNode(getter_AddRefs(*outParent));
|
|
|
|
if ((NS_SUCCEEDED(result)) && (*outParent))
|
1999-04-27 17:14:28 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
result = GetChildOffset(inChild, *outParent, *outOffset);
|
1999-04-27 17:14:28 +00:00
|
|
|
}
|
|
|
|
}
|
1999-02-17 19:42:29 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
// returns the number of things inside aNode.
|
|
|
|
// If aNode is text, returns number of characters. If not, returns number of children nodes.
|
|
|
|
nsresult
|
|
|
|
nsEditor::GetLengthOfDOMNode(nsIDOMNode *aNode, PRUint32 &aCount)
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
aCount = 0;
|
|
|
|
if (!aNode) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
nsresult result=NS_OK;
|
2003-06-30 18:55:06 +00:00
|
|
|
nsCOMPtr<nsIDOMCharacterData>nodeAsChar = do_QueryInterface(aNode);
|
1999-08-09 01:37:50 +00:00
|
|
|
if (nodeAsChar) {
|
|
|
|
nodeAsChar->GetLength(&aCount);
|
|
|
|
}
|
|
|
|
else
|
1999-02-12 17:18:58 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
PRBool hasChildNodes;
|
|
|
|
aNode->HasChildNodes(&hasChildNodes);
|
2003-06-30 18:55:06 +00:00
|
|
|
if (hasChildNodes)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNodeList>nodeList;
|
|
|
|
result = aNode->GetChildNodes(getter_AddRefs(nodeList));
|
|
|
|
if (NS_SUCCEEDED(result) && nodeList) {
|
|
|
|
nodeList->GetLength(&aCount);
|
|
|
|
}
|
1999-02-12 17:18:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2001-04-07 00:45:26 +00:00
|
|
|
|
1999-08-31 13:55:18 +00:00
|
|
|
nsresult
|
|
|
|
nsEditor::GetPriorNode(nsIDOMNode *aParentNode,
|
|
|
|
PRInt32 aOffset,
|
|
|
|
PRBool aEditableNode,
|
2001-08-22 05:32:44 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> *aResultNode,
|
|
|
|
PRBool bNoBlockCrossing)
|
1999-08-31 13:55:18 +00:00
|
|
|
{
|
|
|
|
// just another version of GetPriorNode that takes a {parent, offset}
|
|
|
|
// instead of a node
|
|
|
|
if (!aParentNode || !aResultNode) { return NS_ERROR_NULL_POINTER; }
|
2001-08-22 05:32:44 +00:00
|
|
|
*aResultNode = nsnull;
|
1999-08-31 13:55:18 +00:00
|
|
|
|
1999-09-29 20:08:15 +00:00
|
|
|
// if we are at beginning of node, or it is a textnode, then just look before it
|
|
|
|
if (!aOffset || IsTextNode(aParentNode))
|
1999-08-31 13:55:18 +00:00
|
|
|
{
|
2001-08-22 05:32:44 +00:00
|
|
|
if (bNoBlockCrossing && IsBlockNode(aParentNode))
|
|
|
|
{
|
2003-06-30 18:55:06 +00:00
|
|
|
// if we aren't allowed to cross blocks, don't look before this block
|
|
|
|
return NS_OK;
|
2001-08-22 05:32:44 +00:00
|
|
|
}
|
|
|
|
return GetPriorNode(aParentNode, aEditableNode, aResultNode, bNoBlockCrossing);
|
1999-08-31 13:55:18 +00:00
|
|
|
}
|
|
|
|
|
2003-06-30 18:55:06 +00:00
|
|
|
// else look before the child at 'aOffset'
|
|
|
|
nsCOMPtr<nsIDOMNode> child = GetChildAt(aParentNode, aOffset);
|
|
|
|
if (child)
|
|
|
|
return GetPriorNode(child, aEditableNode, aResultNode, bNoBlockCrossing);
|
|
|
|
|
|
|
|
// unless there isn't one, in which case we are at the end of the node
|
|
|
|
// and want the deep-right child.
|
|
|
|
*aResultNode = GetRightmostChild(aParentNode, bNoBlockCrossing);
|
|
|
|
if (!*aResultNode || !aEditableNode || IsEditable(*aResultNode))
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
// restart the search from the non-editable node we just found
|
|
|
|
nsCOMPtr<nsIDOMNode> notEditableNode = do_QueryInterface(*aResultNode);
|
|
|
|
return GetPriorNode(notEditableNode, aEditableNode, aResultNode, bNoBlockCrossing);
|
|
|
|
}
|
1999-08-31 13:55:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsEditor::GetNextNode(nsIDOMNode *aParentNode,
|
|
|
|
PRInt32 aOffset,
|
|
|
|
PRBool aEditableNode,
|
2001-08-22 05:32:44 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> *aResultNode,
|
|
|
|
PRBool bNoBlockCrossing)
|
1999-08-31 13:55:18 +00:00
|
|
|
{
|
|
|
|
// just another version of GetNextNode that takes a {parent, offset}
|
|
|
|
// instead of a node
|
|
|
|
if (!aParentNode || !aResultNode) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
|
2000-05-09 21:06:49 +00:00
|
|
|
*aResultNode = nsnull;
|
2003-06-30 18:55:06 +00:00
|
|
|
|
1999-09-29 20:08:15 +00:00
|
|
|
// if aParentNode is a text node, use it's location instead
|
|
|
|
if (IsTextNode(aParentNode))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
2000-12-09 04:46:08 +00:00
|
|
|
nsEditor::GetNodeLocation(aParentNode, address_of(parent), &aOffset);
|
1999-09-29 20:08:15 +00:00
|
|
|
aParentNode = parent;
|
|
|
|
aOffset++; // _after_ the text node
|
|
|
|
}
|
1999-08-31 13:55:18 +00:00
|
|
|
// look at the child at 'aOffset'
|
|
|
|
nsCOMPtr<nsIDOMNode> child = GetChildAt(aParentNode, aOffset);
|
|
|
|
if (child)
|
|
|
|
{
|
2001-08-22 05:32:44 +00:00
|
|
|
if (bNoBlockCrossing && IsBlockNode(child))
|
|
|
|
{
|
|
|
|
*aResultNode = child; // return this block
|
2003-06-30 18:55:06 +00:00
|
|
|
return NS_OK;
|
2001-08-22 05:32:44 +00:00
|
|
|
}
|
|
|
|
*aResultNode = GetLeftmostChild(child, bNoBlockCrossing);
|
|
|
|
if (!*aResultNode)
|
|
|
|
{
|
|
|
|
*aResultNode = child;
|
2003-06-30 18:55:06 +00:00
|
|
|
return NS_OK;
|
2001-08-22 05:32:44 +00:00
|
|
|
}
|
2000-05-09 21:06:49 +00:00
|
|
|
if (!IsDescendantOfBody(*aResultNode))
|
|
|
|
{
|
2001-08-22 05:32:44 +00:00
|
|
|
*aResultNode = nsnull;
|
2003-06-30 18:55:06 +00:00
|
|
|
return NS_OK;
|
1999-08-31 13:55:18 +00:00
|
|
|
}
|
2003-06-30 18:55:06 +00:00
|
|
|
|
|
|
|
if (!aEditableNode || IsEditable(*aResultNode))
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
// restart the search from the non-editable node we just found
|
|
|
|
nsCOMPtr<nsIDOMNode> notEditableNode = do_QueryInterface(*aResultNode);
|
|
|
|
return GetNextNode(notEditableNode, aEditableNode, aResultNode, bNoBlockCrossing);
|
1999-08-31 13:55:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// unless there isn't one, in which case we are at the end of the node
|
|
|
|
// and want the next one.
|
2003-06-30 18:55:06 +00:00
|
|
|
if (bNoBlockCrossing && IsBlockNode(aParentNode))
|
1999-08-31 13:55:18 +00:00
|
|
|
{
|
2003-06-30 18:55:06 +00:00
|
|
|
// don't cross out of parent block
|
|
|
|
return NS_OK;
|
1999-08-31 13:55:18 +00:00
|
|
|
}
|
2003-06-30 18:55:06 +00:00
|
|
|
return GetNextNode(aParentNode, aEditableNode, aResultNode, bNoBlockCrossing);
|
1999-08-31 13:55:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-06-16 05:02:43 +00:00
|
|
|
nsresult
|
1999-08-09 01:37:50 +00:00
|
|
|
nsEditor::GetPriorNode(nsIDOMNode *aCurrentNode,
|
|
|
|
PRBool aEditableNode,
|
2001-08-22 05:32:44 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> *aResultNode,
|
|
|
|
PRBool bNoBlockCrossing)
|
1999-06-16 05:02:43 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
nsresult result;
|
|
|
|
if (!aCurrentNode || !aResultNode) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
|
|
|
|
*aResultNode = nsnull; // init out-param
|
|
|
|
|
2001-08-29 21:33:52 +00:00
|
|
|
if (IsRootNode(aCurrentNode))
|
|
|
|
{
|
|
|
|
// Don't allow traversal above the root node! This helps
|
|
|
|
// prevent us from accidentally editing browser content
|
|
|
|
// when the editor is in a text widget.
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-12-09 09:24:33 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> candidate;
|
|
|
|
result = GetPriorNodeImpl(aCurrentNode, aEditableNode, address_of(candidate), bNoBlockCrossing);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2001-12-09 09:24:33 +00:00
|
|
|
|
|
|
|
if (!candidate)
|
|
|
|
{
|
|
|
|
// we could not find a prior node. return null.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
else if (!aEditableNode) *aResultNode = candidate;
|
|
|
|
else if (IsEditable(candidate)) *aResultNode = candidate;
|
|
|
|
else
|
|
|
|
{ // restart the search from the non-editable node we just found
|
|
|
|
nsCOMPtr<nsIDOMNode> notEditableNode = do_QueryInterface(candidate);
|
|
|
|
return GetPriorNode(notEditableNode, aEditableNode, aResultNode, bNoBlockCrossing);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsEditor::GetPriorNodeImpl(nsIDOMNode *aCurrentNode,
|
|
|
|
PRBool aEditableNode,
|
|
|
|
nsCOMPtr<nsIDOMNode> *aResultNode,
|
|
|
|
PRBool bNoBlockCrossing)
|
|
|
|
{
|
2003-06-30 18:55:06 +00:00
|
|
|
// called only by GetPriorNode so we don't need to check params.
|
2001-12-09 09:24:33 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
// if aCurrentNode has a left sibling, return that sibling's rightmost child (or itself if it has no children)
|
2000-03-23 01:14:49 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> prevSibling;
|
2003-06-30 18:55:06 +00:00
|
|
|
nsresult result = aCurrentNode->GetPreviousSibling(getter_AddRefs(prevSibling));
|
2000-03-23 01:14:49 +00:00
|
|
|
if ((NS_SUCCEEDED(result)) && prevSibling)
|
1999-06-16 05:02:43 +00:00
|
|
|
{
|
2001-08-22 05:32:44 +00:00
|
|
|
if (bNoBlockCrossing && IsBlockNode(prevSibling))
|
2000-05-09 21:06:49 +00:00
|
|
|
{
|
2001-08-22 05:32:44 +00:00
|
|
|
// don't look inside prevsib, since it is a block
|
|
|
|
*aResultNode = prevSibling;
|
2001-12-09 09:24:33 +00:00
|
|
|
return NS_OK;
|
2000-05-09 21:06:49 +00:00
|
|
|
}
|
2001-08-22 05:32:44 +00:00
|
|
|
*aResultNode = GetRightmostChild(prevSibling, bNoBlockCrossing);
|
|
|
|
if (!*aResultNode)
|
|
|
|
{
|
|
|
|
*aResultNode = prevSibling;
|
2001-12-09 09:24:33 +00:00
|
|
|
return NS_OK;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
2001-08-22 05:32:44 +00:00
|
|
|
if (!IsDescendantOfBody(*aResultNode))
|
|
|
|
{
|
|
|
|
*aResultNode = nsnull;
|
2001-12-09 09:24:33 +00:00
|
|
|
return NS_OK;
|
1999-06-16 05:02:43 +00:00
|
|
|
}
|
|
|
|
}
|
2001-12-09 09:24:33 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// otherwise, walk up the parent tree until there is a child that comes before
|
|
|
|
// the ancestor of aCurrentNode. Then return that node's rightmost child
|
|
|
|
nsCOMPtr<nsIDOMNode> parent = do_QueryInterface(aCurrentNode);
|
|
|
|
nsCOMPtr<nsIDOMNode> node, notEditableNode;
|
|
|
|
do {
|
|
|
|
node = parent;
|
|
|
|
result = node->GetParentNode(getter_AddRefs(parent));
|
|
|
|
if ((NS_SUCCEEDED(result)) && parent)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
2001-12-09 09:24:33 +00:00
|
|
|
if (!IsDescendantOfBody(parent))
|
2000-05-09 21:06:49 +00:00
|
|
|
{
|
2001-12-09 09:24:33 +00:00
|
|
|
*aResultNode = nsnull;
|
|
|
|
return NS_OK;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
2001-12-09 09:24:33 +00:00
|
|
|
if ((bNoBlockCrossing && IsBlockNode(parent)) || IsRootNode(parent))
|
2001-08-22 05:32:44 +00:00
|
|
|
{
|
2001-12-09 09:24:33 +00:00
|
|
|
// we are at front of block or root, do not step out
|
2001-08-22 05:32:44 +00:00
|
|
|
*aResultNode = nsnull;
|
2001-12-09 09:24:33 +00:00
|
|
|
return NS_OK;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
2001-12-09 09:24:33 +00:00
|
|
|
result = parent->GetPreviousSibling(getter_AddRefs(node));
|
|
|
|
if ((NS_SUCCEEDED(result)) && node)
|
|
|
|
{
|
|
|
|
if (bNoBlockCrossing && IsBlockNode(node))
|
|
|
|
{
|
|
|
|
// prev sibling is a block, do not step into it
|
|
|
|
*aResultNode = node;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
*aResultNode = GetRightmostChild(node, bNoBlockCrossing);
|
|
|
|
if (!*aResultNode) *aResultNode = node;
|
|
|
|
return NS_OK;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
1999-03-14 00:31:35 +00:00
|
|
|
}
|
2001-12-09 09:24:33 +00:00
|
|
|
} while ((NS_SUCCEEDED(result)) && parent && !*aResultNode);
|
|
|
|
}
|
1999-05-05 04:05:19 +00:00
|
|
|
return result;
|
1999-03-14 00:31:35 +00:00
|
|
|
}
|
|
|
|
|
1999-06-25 03:18:42 +00:00
|
|
|
nsresult
|
1999-08-09 01:37:50 +00:00
|
|
|
nsEditor::GetNextNode(nsIDOMNode *aCurrentNode,
|
|
|
|
PRBool aEditableNode,
|
2001-08-22 05:32:44 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> *aResultNode,
|
|
|
|
PRBool bNoBlockCrossing)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
2001-08-22 05:32:44 +00:00
|
|
|
if (!aCurrentNode || !aResultNode) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
|
|
|
|
*aResultNode = nsnull; // init out-param
|
2001-08-29 21:33:52 +00:00
|
|
|
|
|
|
|
if (IsRootNode(aCurrentNode))
|
|
|
|
{
|
|
|
|
// Don't allow traversal above the root node! This helps
|
|
|
|
// prevent us from accidentally editing browser content
|
|
|
|
// when the editor is in a text widget.
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-12-09 09:24:33 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> candidate;
|
2003-06-30 18:55:06 +00:00
|
|
|
nsresult result = GetNextNodeImpl(aCurrentNode, aEditableNode,
|
|
|
|
address_of(candidate), bNoBlockCrossing);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2001-12-09 09:24:33 +00:00
|
|
|
|
|
|
|
if (!candidate)
|
|
|
|
{
|
|
|
|
// we could not find a next node. return null.
|
|
|
|
*aResultNode = nsnull;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
else if (!aEditableNode) *aResultNode = candidate;
|
|
|
|
else if (IsEditable(candidate)) *aResultNode = candidate;
|
|
|
|
else
|
|
|
|
{ // restart the search from the non-editable node we just found
|
|
|
|
nsCOMPtr<nsIDOMNode> notEditableNode = do_QueryInterface(candidate);
|
|
|
|
return GetNextNode(notEditableNode, aEditableNode, aResultNode, bNoBlockCrossing);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsEditor::GetNextNodeImpl(nsIDOMNode *aCurrentNode,
|
|
|
|
PRBool aEditableNode,
|
|
|
|
nsCOMPtr<nsIDOMNode> *aResultNode,
|
|
|
|
PRBool bNoBlockCrossing)
|
|
|
|
{
|
2003-06-30 18:55:06 +00:00
|
|
|
// called only by GetNextNode so we don't need to check params.
|
2001-12-09 09:24:33 +00:00
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
// if aCurrentNode has a right sibling, return that sibling's leftmost child (or itself if it has no children)
|
2000-03-24 00:26:47 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> nextSibling;
|
2003-06-30 18:55:06 +00:00
|
|
|
nsresult result = aCurrentNode->GetNextSibling(getter_AddRefs(nextSibling));
|
2000-03-24 00:26:47 +00:00
|
|
|
if ((NS_SUCCEEDED(result)) && nextSibling)
|
1999-03-02 05:30:53 +00:00
|
|
|
{
|
2001-08-22 05:32:44 +00:00
|
|
|
if (bNoBlockCrossing && IsBlockNode(nextSibling))
|
2000-05-09 21:06:49 +00:00
|
|
|
{
|
2001-08-22 05:32:44 +00:00
|
|
|
// next sibling is a block, do not step into it
|
|
|
|
*aResultNode = nextSibling;
|
2001-12-09 09:24:33 +00:00
|
|
|
return NS_OK;
|
2000-05-09 21:06:49 +00:00
|
|
|
}
|
2001-08-22 05:32:44 +00:00
|
|
|
*aResultNode = GetLeftmostChild(nextSibling, bNoBlockCrossing);
|
|
|
|
if (!*aResultNode)
|
|
|
|
{
|
|
|
|
*aResultNode = nextSibling;
|
2001-12-09 09:24:33 +00:00
|
|
|
return NS_OK;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
2001-08-22 05:32:44 +00:00
|
|
|
if (!IsDescendantOfBody(*aResultNode))
|
|
|
|
{
|
|
|
|
*aResultNode = nsnull;
|
2001-12-09 09:24:33 +00:00
|
|
|
return NS_OK;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
}
|
2001-12-09 09:24:33 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// otherwise, walk up the parent tree until there is a child that comes after
|
|
|
|
// the ancestor of aCurrentNode. Then return that node's leftmost child
|
|
|
|
nsCOMPtr<nsIDOMNode> parent(do_QueryInterface(aCurrentNode));
|
|
|
|
nsCOMPtr<nsIDOMNode> node, notEditableNode;
|
|
|
|
do {
|
|
|
|
node = parent;
|
|
|
|
result = node->GetParentNode(getter_AddRefs(parent));
|
|
|
|
if ((NS_SUCCEEDED(result)) && parent)
|
1999-05-05 04:05:19 +00:00
|
|
|
{
|
2001-12-09 09:24:33 +00:00
|
|
|
if (!IsDescendantOfBody(parent))
|
2000-05-09 21:06:49 +00:00
|
|
|
{
|
2001-12-09 09:24:33 +00:00
|
|
|
*aResultNode = nsnull;
|
|
|
|
return NS_OK;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
2001-12-09 09:24:33 +00:00
|
|
|
if ((bNoBlockCrossing && IsBlockNode(parent)) || IsRootNode(parent))
|
2001-08-22 05:32:44 +00:00
|
|
|
{
|
2001-12-09 09:24:33 +00:00
|
|
|
// we are at end of block or root, do not step out
|
2001-08-22 05:32:44 +00:00
|
|
|
*aResultNode = nsnull;
|
2001-12-09 09:24:33 +00:00
|
|
|
return NS_OK;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
2001-12-09 09:24:33 +00:00
|
|
|
result = parent->GetNextSibling(getter_AddRefs(node));
|
|
|
|
if ((NS_SUCCEEDED(result)) && node)
|
|
|
|
{
|
|
|
|
if (bNoBlockCrossing && IsBlockNode(node))
|
|
|
|
{
|
|
|
|
// next sibling is a block, do not step into it
|
|
|
|
*aResultNode = node;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
*aResultNode = GetLeftmostChild(node, bNoBlockCrossing);
|
|
|
|
if (!*aResultNode) *aResultNode = node;
|
|
|
|
return NS_OK;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
1999-03-02 05:30:53 +00:00
|
|
|
}
|
2001-12-09 09:24:33 +00:00
|
|
|
} while ((NS_SUCCEEDED(result)) && parent);
|
|
|
|
}
|
1999-06-25 03:18:42 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2001-12-09 09:24:33 +00:00
|
|
|
|
2001-08-22 05:32:44 +00:00
|
|
|
nsCOMPtr<nsIDOMNode>
|
2002-05-14 00:05:37 +00:00
|
|
|
nsEditor::GetRightmostChild(nsIDOMNode *aCurrentNode,
|
|
|
|
PRBool bNoBlockCrossing)
|
1999-06-25 03:18:42 +00:00
|
|
|
{
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(aCurrentNode, nsnull);
|
2001-08-22 05:32:44 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> resultNode, temp=aCurrentNode;
|
1999-08-09 01:37:50 +00:00
|
|
|
PRBool hasChildren;
|
2001-08-22 05:32:44 +00:00
|
|
|
aCurrentNode->HasChildNodes(&hasChildren);
|
|
|
|
while (hasChildren)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
|
|
|
temp->GetLastChild(getter_AddRefs(resultNode));
|
2001-08-22 05:32:44 +00:00
|
|
|
if (resultNode)
|
|
|
|
{
|
|
|
|
if (bNoBlockCrossing && IsBlockNode(resultNode))
|
|
|
|
return resultNode;
|
|
|
|
resultNode->HasChildNodes(&hasChildren);
|
|
|
|
temp = resultNode;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
hasChildren = PR_FALSE;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
1999-06-25 03:18:42 +00:00
|
|
|
|
2001-08-22 05:32:44 +00:00
|
|
|
return resultNode;
|
1999-05-05 04:05:19 +00:00
|
|
|
}
|
|
|
|
|
2001-08-22 05:32:44 +00:00
|
|
|
nsCOMPtr<nsIDOMNode>
|
2002-05-14 00:05:37 +00:00
|
|
|
nsEditor::GetLeftmostChild(nsIDOMNode *aCurrentNode,
|
|
|
|
PRBool bNoBlockCrossing)
|
1999-05-05 04:05:19 +00:00
|
|
|
{
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(aCurrentNode, nsnull);
|
2001-08-22 05:32:44 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> resultNode, temp=aCurrentNode;
|
1999-08-09 01:37:50 +00:00
|
|
|
PRBool hasChildren;
|
2001-08-22 05:32:44 +00:00
|
|
|
aCurrentNode->HasChildNodes(&hasChildren);
|
|
|
|
while (hasChildren)
|
1999-05-05 04:05:19 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
temp->GetFirstChild(getter_AddRefs(resultNode));
|
2001-08-22 05:32:44 +00:00
|
|
|
if (resultNode)
|
|
|
|
{
|
|
|
|
if (bNoBlockCrossing && IsBlockNode(resultNode))
|
|
|
|
return resultNode;
|
|
|
|
resultNode->HasChildNodes(&hasChildren);
|
|
|
|
temp = resultNode;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
hasChildren = PR_FALSE;
|
1999-05-05 04:05:19 +00:00
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2001-08-22 05:32:44 +00:00
|
|
|
return resultNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsEditor::IsBlockNode(nsIDOMNode *aNode)
|
|
|
|
{
|
|
|
|
// stub to be overridden in nsHTMLEditor.
|
2010-04-29 19:01:11 +00:00
|
|
|
// screwing around with the class hierarchy here in order
|
2001-08-22 05:32:44 +00:00
|
|
|
// to not duplicate the code in GetNextNode/GetPrevNode
|
|
|
|
// across both nsEditor/nsHTMLEditor.
|
|
|
|
return PR_FALSE;
|
1999-05-05 04:05:19 +00:00
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
PRBool
|
2002-03-23 22:16:54 +00:00
|
|
|
nsEditor::CanContainTag(nsIDOMNode* aParent, const nsAString &aChildTag)
|
1999-05-05 04:05:19 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
nsCOMPtr<nsIDOMElement> parentElement = do_QueryInterface(aParent);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(parentElement, PR_FALSE);
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2003-06-30 18:55:06 +00:00
|
|
|
nsAutoString parentStringTag;
|
1999-08-09 01:37:50 +00:00
|
|
|
parentElement->GetTagName(parentStringTag);
|
2000-02-08 12:53:34 +00:00
|
|
|
return TagCanContainTag(parentStringTag, aChildTag);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
2002-03-23 22:16:54 +00:00
|
|
|
nsEditor::TagCanContain(const nsAString &aParentTag, nsIDOMNode* aChild)
|
2000-02-08 12:53:34 +00:00
|
|
|
{
|
|
|
|
nsAutoString childStringTag;
|
|
|
|
|
2000-03-24 00:26:47 +00:00
|
|
|
if (IsTextNode(aChild))
|
|
|
|
{
|
2005-06-16 13:10:58 +00:00
|
|
|
childStringTag.AssignLiteral("#text");
|
2000-03-24 00:26:47 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMElement> childElement = do_QueryInterface(aChild);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(childElement, PR_FALSE);
|
2000-03-24 00:26:47 +00:00
|
|
|
childElement->GetTagName(childStringTag);
|
|
|
|
}
|
2000-02-08 12:53:34 +00:00
|
|
|
return TagCanContainTag(aParentTag, childStringTag);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
2002-03-23 22:16:54 +00:00
|
|
|
nsEditor::TagCanContainTag(const nsAString &aParentTag, const nsAString &aChildTag)
|
2000-02-08 12:53:34 +00:00
|
|
|
{
|
2005-09-05 14:18:56 +00:00
|
|
|
return PR_TRUE;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
|
2001-08-28 18:21:12 +00:00
|
|
|
PRBool
|
|
|
|
nsEditor::IsRootNode(nsIDOMNode *inNode)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(inNode, PR_FALSE);
|
2001-08-28 18:21:12 +00:00
|
|
|
|
2005-03-24 19:00:01 +00:00
|
|
|
nsIDOMElement *rootElement = GetRoot();
|
2001-08-28 18:21:12 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(rootElement);
|
2005-03-24 19:00:01 +00:00
|
|
|
|
|
|
|
return inNode == rootNode;
|
2001-08-28 18:21:12 +00:00
|
|
|
}
|
|
|
|
|
2000-05-09 21:06:49 +00:00
|
|
|
PRBool
|
|
|
|
nsEditor::IsDescendantOfBody(nsIDOMNode *inNode)
|
|
|
|
{
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(inNode, PR_FALSE);
|
2005-03-24 19:00:01 +00:00
|
|
|
nsIDOMElement *rootElement = GetRoot();
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(rootElement, PR_FALSE);
|
2005-03-24 19:00:01 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> root = do_QueryInterface(rootElement);
|
|
|
|
|
2000-05-09 21:06:49 +00:00
|
|
|
if (inNode == root.get()) return PR_TRUE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> parent, node = do_QueryInterface(inNode);
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
node->GetParentNode(getter_AddRefs(parent));
|
|
|
|
if (parent == root) return PR_TRUE;
|
|
|
|
node = parent;
|
|
|
|
} while (parent);
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
1999-09-29 20:08:15 +00:00
|
|
|
PRBool
|
|
|
|
nsEditor::IsContainer(nsIDOMNode *aNode)
|
|
|
|
{
|
2005-09-05 14:18:56 +00:00
|
|
|
return aNode ? PR_TRUE : PR_FALSE;
|
1999-09-29 20:08:15 +00:00
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2003-06-11 11:50:36 +00:00
|
|
|
PRBool
|
|
|
|
nsEditor::IsTextInDirtyFrameVisible(nsIDOMNode *aNode)
|
|
|
|
{
|
|
|
|
// virtual method
|
|
|
|
//
|
|
|
|
// If this is a simple non-html editor,
|
|
|
|
// the best we can do is to assume it's visible.
|
|
|
|
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
PRBool
|
|
|
|
nsEditor::IsEditable(nsIDOMNode *aNode)
|
|
|
|
{
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(aNode, PR_FALSE);
|
2000-01-18 23:45:35 +00:00
|
|
|
|
2007-06-28 02:48:16 +00:00
|
|
|
if (IsMozEditorBogusNode(aNode) || !IsModifiableNode(aNode)) return PR_FALSE;
|
|
|
|
|
2001-06-12 22:35:28 +00:00
|
|
|
// see if it has a frame. If so, we'll edit it.
|
|
|
|
// special case for textnodes: frame must have width.
|
2003-06-30 18:55:06 +00:00
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
|
1999-08-09 01:37:50 +00:00
|
|
|
if (content)
|
|
|
|
{
|
2009-12-24 21:20:06 +00:00
|
|
|
nsIFrame *resultFrame = content->GetPrimaryFrame();
|
2005-08-22 22:24:29 +00:00
|
|
|
if (!resultFrame) // if it has no frame, it is not editable
|
1999-08-09 01:37:50 +00:00
|
|
|
return PR_FALSE;
|
2006-07-19 04:36:36 +00:00
|
|
|
NS_ASSERTION(content->IsNodeOfType(nsINode::eTEXT) ||
|
2010-04-30 13:12:06 +00:00
|
|
|
content->IsElement(),
|
2006-07-19 04:36:36 +00:00
|
|
|
"frame for non element-or-text?");
|
|
|
|
if (!content->IsNodeOfType(nsINode::eTEXT))
|
2001-06-12 22:35:28 +00:00
|
|
|
return PR_TRUE; // not a text node; has a frame
|
2009-10-19 08:01:15 +00:00
|
|
|
|
|
|
|
// test the textframe and all its non-fluid continuations
|
|
|
|
while (resultFrame) {
|
|
|
|
if (resultFrame->GetStateBits() & NS_FRAME_IS_DIRTY) // we can only trust width data for undirty frames
|
|
|
|
{
|
|
|
|
// In the past a comment said:
|
|
|
|
// "assume all text nodes with dirty frames are editable"
|
|
|
|
// Nowadays we use a virtual function, that assumes TRUE
|
|
|
|
// in the simple editor world,
|
|
|
|
// and uses enhanced logic to find out in the HTML world.
|
|
|
|
return IsTextInDirtyFrameVisible(aNode);
|
|
|
|
}
|
|
|
|
if (resultFrame->GetSize().width > 0)
|
|
|
|
return PR_TRUE; // text node has width
|
|
|
|
resultFrame = resultFrame->GetNextContinuation();
|
2003-06-11 11:50:36 +00:00
|
|
|
}
|
2001-06-12 22:35:28 +00:00
|
|
|
}
|
|
|
|
return PR_FALSE; // didn't pass any editability test
|
1999-05-05 04:05:19 +00:00
|
|
|
}
|
|
|
|
|
2000-01-18 23:45:35 +00:00
|
|
|
PRBool
|
|
|
|
nsEditor::IsMozEditorBogusNode(nsIDOMNode *aNode)
|
|
|
|
{
|
2010-05-03 13:23:36 +00:00
|
|
|
nsCOMPtr<nsIContent> element = do_QueryInterface(aNode);
|
|
|
|
return element &&
|
|
|
|
element->AttrValueIs(kNameSpaceID_None, kMOZEditorBogusNodeAttrAtom,
|
|
|
|
kMOZEditorBogusNodeValue, eCaseMatters);
|
2000-01-18 23:45:35 +00:00
|
|
|
}
|
|
|
|
|
1999-05-05 04:05:19 +00:00
|
|
|
nsresult
|
1999-08-09 01:37:50 +00:00
|
|
|
nsEditor::CountEditableChildren(nsIDOMNode *aNode, PRUint32 &outCount)
|
1999-05-05 04:05:19 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
outCount = 0;
|
|
|
|
if (!aNode) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
nsresult res=NS_OK;
|
|
|
|
PRBool hasChildNodes;
|
|
|
|
aNode->HasChildNodes(&hasChildNodes);
|
2003-06-30 18:55:06 +00:00
|
|
|
if (hasChildNodes)
|
1999-05-05 04:05:19 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
nsCOMPtr<nsIDOMNodeList>nodeList;
|
|
|
|
res = aNode->GetChildNodes(getter_AddRefs(nodeList));
|
|
|
|
if (NS_SUCCEEDED(res) && nodeList)
|
1999-05-05 04:05:19 +00:00
|
|
|
{
|
2003-06-30 18:55:06 +00:00
|
|
|
PRUint32 i;
|
|
|
|
PRUint32 len;
|
1999-08-09 01:37:50 +00:00
|
|
|
nodeList->GetLength(&len);
|
|
|
|
for (i=0 ; i<len; i++)
|
1999-05-05 04:05:19 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> child;
|
|
|
|
res = nodeList->Item((PRInt32)i, getter_AddRefs(child));
|
|
|
|
if ((NS_SUCCEEDED(res)) && (child))
|
1999-05-05 04:05:19 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
if (IsEditable(child))
|
1999-05-05 04:05:19 +00:00
|
|
|
{
|
1999-08-09 01:37:50 +00:00
|
|
|
outCount++;
|
1999-05-05 04:05:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
else if (!nodeList)
|
|
|
|
res = NS_ERROR_NULL_POINTER;
|
1999-05-05 04:05:19 +00:00
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
return res;
|
1999-05-05 04:05:19 +00:00
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
//END nsEditor static utility methods
|
1999-05-05 04:05:19 +00:00
|
|
|
|
1999-05-05 04:51:54 +00:00
|
|
|
|
2001-12-10 15:23:11 +00:00
|
|
|
NS_IMETHODIMP nsEditor::IncrementModificationCount(PRInt32 inNumMods)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
2001-12-10 15:23:11 +00:00
|
|
|
PRUint32 oldModCount = mModCount;
|
1999-05-05 04:05:19 +00:00
|
|
|
|
2001-12-10 15:23:11 +00:00
|
|
|
mModCount += inNumMods;
|
|
|
|
|
|
|
|
if ((oldModCount == 0 && mModCount != 0)
|
|
|
|
|| (oldModCount != 0 && mModCount == 0))
|
|
|
|
NotifyDocumentListeners(eDocumentStateChanged);
|
1999-08-09 01:37:50 +00:00
|
|
|
return NS_OK;
|
1999-05-12 22:24:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-10 15:23:11 +00:00
|
|
|
NS_IMETHODIMP nsEditor::GetModificationCount(PRInt32 *outModCount)
|
1999-05-12 22:24:47 +00:00
|
|
|
{
|
2001-12-10 15:23:11 +00:00
|
|
|
NS_ENSURE_ARG_POINTER(outModCount);
|
|
|
|
*outModCount = mModCount;
|
1999-05-12 22:24:47 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-10 15:23:11 +00:00
|
|
|
NS_IMETHODIMP nsEditor::ResetModificationCount()
|
1999-05-12 22:24:47 +00:00
|
|
|
{
|
2001-12-10 15:23:11 +00:00
|
|
|
PRBool doNotify = (mModCount != 0);
|
1999-05-12 22:24:47 +00:00
|
|
|
|
2001-12-10 15:23:11 +00:00
|
|
|
mModCount = 0;
|
|
|
|
|
|
|
|
if (doNotify)
|
|
|
|
NotifyDocumentListeners(eDocumentStateChanged);
|
1999-05-12 22:24:47 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-05-05 04:05:19 +00:00
|
|
|
//END nsEditor Private methods
|
1999-02-12 17:18:58 +00:00
|
|
|
|
1999-08-25 10:51:55 +00:00
|
|
|
|
|
|
|
|
1999-05-17 12:22:31 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetTag: digs out the atom for the tag of this node
|
|
|
|
//
|
2003-11-19 01:20:56 +00:00
|
|
|
nsIAtom *
|
1999-05-17 12:22:31 +00:00
|
|
|
nsEditor::GetTag(nsIDOMNode *aNode)
|
|
|
|
{
|
2003-11-19 01:20:56 +00:00
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
|
|
|
|
|
|
|
|
if (!content)
|
1999-05-17 12:22:31 +00:00
|
|
|
{
|
2003-11-19 01:20:56 +00:00
|
|
|
NS_ASSERTION(aNode, "null node passed to nsEditor::Tag()");
|
|
|
|
|
|
|
|
return nsnull;
|
1999-05-17 12:22:31 +00:00
|
|
|
}
|
|
|
|
|
2003-11-19 01:20:56 +00:00
|
|
|
return content->Tag();
|
1999-05-17 12:22:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-28 21:17:30 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetTagString: digs out string for the tag of this node
|
|
|
|
//
|
|
|
|
nsresult
|
2002-03-23 22:16:54 +00:00
|
|
|
nsEditor::GetTagString(nsIDOMNode *aNode, nsAString& outString)
|
1999-05-28 21:17:30 +00:00
|
|
|
{
|
|
|
|
if (!aNode)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("null node passed to nsEditor::GetTag()");
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
|
|
|
|
2003-11-19 01:20:56 +00:00
|
|
|
nsIAtom *atom = GetTag(aNode);
|
|
|
|
if (!atom)
|
1999-05-28 21:17:30 +00:00
|
|
|
{
|
2003-11-19 01:20:56 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
1999-05-28 21:17:30 +00:00
|
|
|
}
|
2003-11-19 01:20:56 +00:00
|
|
|
|
|
|
|
atom->ToString(outString);
|
|
|
|
return NS_OK;
|
1999-05-28 21:17:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-17 12:22:31 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// NodesSameType: do these nodes have the same tag?
|
|
|
|
//
|
|
|
|
PRBool
|
|
|
|
nsEditor::NodesSameType(nsIDOMNode *aNode1, nsIDOMNode *aNode2)
|
|
|
|
{
|
|
|
|
if (!aNode1 || !aNode2)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("null node passed to nsEditor::NodesSameType()");
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
2003-11-19 01:20:56 +00:00
|
|
|
return GetTag(aNode1) == GetTag(aNode2);
|
1999-05-17 12:22:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// IsTextOrElementNode: true if node of dom type element or text
|
|
|
|
//
|
|
|
|
PRBool
|
|
|
|
nsEditor::IsTextOrElementNode(nsIDOMNode *aNode)
|
|
|
|
{
|
|
|
|
if (!aNode)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("null node passed to IsTextOrElementNode()");
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint16 nodeType;
|
|
|
|
aNode->GetNodeType(&nodeType);
|
2003-06-30 18:55:06 +00:00
|
|
|
return ((nodeType == nsIDOMNode::ELEMENT_NODE) || (nodeType == nsIDOMNode::TEXT_NODE));
|
1999-05-17 12:22:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// IsTextNode: true if node of dom type text
|
|
|
|
//
|
|
|
|
PRBool
|
|
|
|
nsEditor::IsTextNode(nsIDOMNode *aNode)
|
|
|
|
{
|
|
|
|
if (!aNode)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("null node passed to IsTextNode()");
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint16 nodeType;
|
|
|
|
aNode->GetNodeType(&nodeType);
|
2003-06-30 18:55:06 +00:00
|
|
|
return (nodeType == nsIDOMNode::TEXT_NODE);
|
1999-05-17 12:22:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetIndexOf: returns the position index of the node in the parent
|
|
|
|
//
|
|
|
|
PRInt32
|
|
|
|
nsEditor::GetIndexOf(nsIDOMNode *parent, nsIDOMNode *child)
|
|
|
|
{
|
2009-12-30 08:17:44 +00:00
|
|
|
nsCOMPtr<nsINode> parentNode = do_QueryInterface(parent);
|
|
|
|
NS_PRECONDITION(parentNode, "null parentNode in nsEditor::GetIndexOf");
|
|
|
|
NS_PRECONDITION(parentNode->IsNodeOfType(nsINode::eCONTENT) ||
|
|
|
|
parentNode->IsNodeOfType(nsINode::eDOCUMENT),
|
|
|
|
"The parent node must be an element node or a document node");
|
|
|
|
|
1999-05-17 12:22:31 +00:00
|
|
|
nsCOMPtr<nsIContent> cChild = do_QueryInterface(child);
|
|
|
|
NS_PRECONDITION(cChild, "null content in nsEditor::GetIndexOf");
|
2003-09-27 04:18:26 +00:00
|
|
|
|
2009-12-30 08:17:44 +00:00
|
|
|
return parentNode->IndexOf(cChild);
|
1999-05-17 12:22:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetChildAt: returns the node at this position index in the parent
|
|
|
|
//
|
|
|
|
nsCOMPtr<nsIDOMNode>
|
|
|
|
nsEditor::GetChildAt(nsIDOMNode *aParent, PRInt32 aOffset)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> resultNode;
|
|
|
|
|
2003-09-27 04:18:26 +00:00
|
|
|
nsCOMPtr<nsIContent> parent = do_QueryInterface(aParent);
|
|
|
|
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(parent, resultNode);
|
2003-09-27 04:18:26 +00:00
|
|
|
|
|
|
|
resultNode = do_QueryInterface(parent->GetChildAt(aOffset));
|
|
|
|
|
1999-05-17 12:22:31 +00:00
|
|
|
return resultNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetStartNodeAndOffset: returns whatever the start parent & offset is of
|
|
|
|
// the first range in the selection.
|
|
|
|
nsresult
|
2000-09-14 11:45:01 +00:00
|
|
|
nsEditor::GetStartNodeAndOffset(nsISelection *aSelection,
|
2010-06-11 02:46:51 +00:00
|
|
|
nsIDOMNode **outStartNode,
|
1999-05-17 12:22:31 +00:00
|
|
|
PRInt32 *outStartOffset)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(outStartNode && outStartOffset && aSelection, NS_ERROR_NULL_POINTER);
|
2003-06-30 18:55:06 +00:00
|
|
|
|
2010-06-11 02:46:51 +00:00
|
|
|
*outStartNode = nsnull;
|
|
|
|
|
2003-06-30 18:55:06 +00:00
|
|
|
// brade: set outStartNode to null or ?
|
|
|
|
|
|
|
|
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(aSelection));
|
1999-05-17 12:22:31 +00:00
|
|
|
nsCOMPtr<nsIEnumerator> enumerator;
|
2003-06-30 18:55:06 +00:00
|
|
|
nsresult result = selPrivate->GetEnumerator(getter_AddRefs(enumerator));
|
2010-06-18 21:01:08 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
|
|
|
NS_ENSURE_TRUE(enumerator, NS_ERROR_FAILURE);
|
|
|
|
|
1999-05-17 12:22:31 +00:00
|
|
|
enumerator->First();
|
1999-07-25 18:14:44 +00:00
|
|
|
nsCOMPtr<nsISupports> currentItem;
|
2010-06-18 21:01:08 +00:00
|
|
|
result = enumerator->CurrentItem(getter_AddRefs(currentItem));
|
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
1999-05-17 12:22:31 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
|
2010-06-18 21:01:08 +00:00
|
|
|
|
|
|
|
result = range->GetStartContainer(outStartNode);
|
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
|
|
|
|
|
|
|
result = range->GetStartOffset(outStartOffset);
|
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
|
|
|
|
1999-05-17 12:22:31 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetEndNodeAndOffset: returns whatever the end parent & offset is of
|
|
|
|
// the first range in the selection.
|
|
|
|
nsresult
|
2000-09-14 11:45:01 +00:00
|
|
|
nsEditor::GetEndNodeAndOffset(nsISelection *aSelection,
|
2010-06-11 02:46:51 +00:00
|
|
|
nsIDOMNode **outEndNode,
|
1999-05-17 12:22:31 +00:00
|
|
|
PRInt32 *outEndOffset)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(outEndNode && outEndOffset, NS_ERROR_NULL_POINTER);
|
2010-06-11 02:46:51 +00:00
|
|
|
|
|
|
|
*outEndNode = nsnull;
|
1999-05-17 12:22:31 +00:00
|
|
|
|
2003-06-30 18:55:06 +00:00
|
|
|
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(aSelection));
|
1999-05-17 12:22:31 +00:00
|
|
|
nsCOMPtr<nsIEnumerator> enumerator;
|
2000-09-14 11:45:01 +00:00
|
|
|
nsresult result = selPrivate->GetEnumerator(getter_AddRefs(enumerator));
|
1999-07-15 19:13:46 +00:00
|
|
|
if (NS_FAILED(result) || !enumerator)
|
1999-05-17 12:22:31 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
enumerator->First();
|
1999-07-25 18:14:44 +00:00
|
|
|
nsCOMPtr<nsISupports> currentItem;
|
2003-06-30 18:55:06 +00:00
|
|
|
if (NS_FAILED(enumerator->CurrentItem(getter_AddRefs(currentItem))))
|
1999-05-17 12:22:31 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
|
1999-05-17 12:22:31 +00:00
|
|
|
|
2010-06-11 02:46:51 +00:00
|
|
|
if (NS_FAILED(range->GetEndContainer(outEndNode)))
|
1999-05-17 12:22:31 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
if (NS_FAILED(range->GetEndOffset(outEndOffset)))
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// IsPreformatted: checks the style info for the node for the preformatted
|
|
|
|
// text style.
|
|
|
|
nsresult
|
|
|
|
nsEditor::IsPreformatted(nsIDOMNode *aNode, PRBool *aResult)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
|
|
|
|
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(aResult && content, NS_ERROR_NULL_POINTER);
|
1999-05-17 12:22:31 +00:00
|
|
|
|
1999-08-25 10:51:55 +00:00
|
|
|
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
2003-01-14 22:08:42 +00:00
|
|
|
|
2010-05-21 20:36:42 +00:00
|
|
|
nsRefPtr<nsStyleContext> elementStyle;
|
|
|
|
if (content->IsElement()) {
|
|
|
|
elementStyle = nsComputedDOMStyle::GetStyleContextForElement(content->AsElement(),
|
|
|
|
nsnull,
|
|
|
|
ps);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!elementStyle)
|
2000-03-25 02:27:57 +00:00
|
|
|
{
|
|
|
|
// Consider nodes without a style context to be NOT preformatted:
|
|
|
|
// For instance, this is true of JS tags inside the body (which show
|
|
|
|
// up as #text nodes but have no style context).
|
|
|
|
*aResult = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-05-17 12:22:31 +00:00
|
|
|
|
2010-05-21 20:36:42 +00:00
|
|
|
const nsStyleText* styleText = elementStyle->GetStyleText();
|
1999-05-17 12:22:31 +00:00
|
|
|
|
2008-02-20 02:07:48 +00:00
|
|
|
*aResult = styleText->WhiteSpaceIsSignificant();
|
1999-05-17 12:22:31 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// SplitNodeDeep: this splits a node "deeply", splitting children as
|
|
|
|
// appropriate. The place to split is represented by
|
|
|
|
// a dom point at {splitPointParent, splitPointOffset}.
|
|
|
|
// That dom point must be inside aNode, which is the node to
|
1999-11-25 00:16:56 +00:00
|
|
|
// split. outOffset is set to the offset in the parent of aNode where
|
1999-08-09 21:45:52 +00:00
|
|
|
// the split terminates - where you would want to insert
|
2005-11-25 08:16:51 +00:00
|
|
|
// a new element, for instance, if that's why you were splitting
|
1999-08-09 21:45:52 +00:00
|
|
|
// the node.
|
|
|
|
//
|
1999-05-17 12:22:31 +00:00
|
|
|
nsresult
|
|
|
|
nsEditor::SplitNodeDeep(nsIDOMNode *aNode,
|
1999-05-28 21:17:30 +00:00
|
|
|
nsIDOMNode *aSplitPointParent,
|
1999-08-09 21:45:52 +00:00
|
|
|
PRInt32 aSplitPointOffset,
|
2000-04-24 11:51:12 +00:00
|
|
|
PRInt32 *outOffset,
|
2000-08-26 04:03:50 +00:00
|
|
|
PRBool aNoEmptyContainers,
|
2000-04-24 11:51:12 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> *outLeftNode,
|
|
|
|
nsCOMPtr<nsIDOMNode> *outRightNode)
|
1999-05-17 12:22:31 +00:00
|
|
|
{
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(aNode && aSplitPointParent && outOffset, NS_ERROR_NULL_POINTER);
|
1999-08-09 21:45:52 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> tempNode, parentNode;
|
1999-05-17 12:22:31 +00:00
|
|
|
PRInt32 offset = aSplitPointOffset;
|
1999-08-09 21:45:52 +00:00
|
|
|
nsresult res;
|
1999-05-17 12:22:31 +00:00
|
|
|
|
2000-04-24 11:51:12 +00:00
|
|
|
if (outLeftNode) *outLeftNode = nsnull;
|
|
|
|
if (outRightNode) *outRightNode = nsnull;
|
|
|
|
|
2003-06-30 18:55:06 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> nodeToSplit = do_QueryInterface(aSplitPointParent);
|
1999-05-17 12:22:31 +00:00
|
|
|
while (nodeToSplit)
|
|
|
|
{
|
1999-08-31 13:55:18 +00:00
|
|
|
// need to insert rules code call here to do things like
|
1999-08-09 21:45:52 +00:00
|
|
|
// not split a list if you are after the last <li> or before the first, etc.
|
|
|
|
// for now we just have some smarts about unneccessarily splitting
|
|
|
|
// textnodes, which should be universal enough to put straight in
|
|
|
|
// this nsEditor routine.
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(nodeToSplit);
|
2000-08-26 04:03:50 +00:00
|
|
|
PRUint32 len;
|
1999-08-09 21:45:52 +00:00
|
|
|
PRBool bDoSplit = PR_FALSE;
|
2000-08-26 04:03:50 +00:00
|
|
|
res = GetLengthOfDOMNode(nodeToSplit, len);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
1999-08-09 21:45:52 +00:00
|
|
|
|
2000-08-26 04:03:50 +00:00
|
|
|
if (!(aNoEmptyContainers || nodeAsText) || (offset && (offset != (PRInt32)len)))
|
1999-08-09 21:45:52 +00:00
|
|
|
{
|
|
|
|
bDoSplit = PR_TRUE;
|
1999-08-18 08:13:06 +00:00
|
|
|
res = SplitNode(nodeToSplit, offset, getter_AddRefs(tempNode));
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-04-24 11:51:12 +00:00
|
|
|
if (outRightNode) *outRightNode = nodeToSplit;
|
|
|
|
if (outLeftNode) *outLeftNode = tempNode;
|
1999-08-09 21:45:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
res = nodeToSplit->GetParentNode(getter_AddRefs(parentNode));
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(parentNode, NS_ERROR_FAILURE);
|
2003-06-30 18:55:06 +00:00
|
|
|
|
1999-08-09 21:45:52 +00:00
|
|
|
if (!bDoSplit && offset) // must be "end of text node" case, we didn't split it, just move past it
|
2000-04-24 11:51:12 +00:00
|
|
|
{
|
1999-08-09 21:45:52 +00:00
|
|
|
offset = GetIndexOf(parentNode, nodeToSplit) +1;
|
2000-04-24 11:51:12 +00:00
|
|
|
if (outLeftNode) *outLeftNode = nodeToSplit;
|
|
|
|
}
|
1999-08-09 21:45:52 +00:00
|
|
|
else
|
2000-04-24 11:51:12 +00:00
|
|
|
{
|
1999-08-09 21:45:52 +00:00
|
|
|
offset = GetIndexOf(parentNode, nodeToSplit);
|
2000-04-24 11:51:12 +00:00
|
|
|
if (outRightNode) *outRightNode = nodeToSplit;
|
|
|
|
}
|
1999-05-17 12:22:31 +00:00
|
|
|
|
|
|
|
if (nodeToSplit.get() == aNode) // we split all the way up to (and including) aNode; we're done
|
|
|
|
break;
|
|
|
|
|
1999-08-09 21:45:52 +00:00
|
|
|
nodeToSplit = parentNode;
|
1999-05-17 12:22:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!nodeToSplit)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("null node obtained in nsEditor::SplitNodeDeep()");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
1999-08-09 21:45:52 +00:00
|
|
|
*outOffset = offset;
|
|
|
|
|
1999-05-17 12:22:31 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// JoinNodeDeep: this joins two like nodes "deeply", joining children as
|
|
|
|
// appropriate.
|
|
|
|
nsresult
|
|
|
|
nsEditor::JoinNodeDeep(nsIDOMNode *aLeftNode,
|
1999-05-28 21:17:30 +00:00
|
|
|
nsIDOMNode *aRightNode,
|
1999-08-31 13:55:18 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> *aOutJoinNode,
|
|
|
|
PRInt32 *outOffset)
|
1999-05-17 12:22:31 +00:00
|
|
|
{
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(aLeftNode && aRightNode && aOutJoinNode && outOffset, NS_ERROR_NULL_POINTER);
|
1999-05-17 12:22:31 +00:00
|
|
|
|
|
|
|
// while the rightmost children and their descendants of the left node
|
|
|
|
// match the leftmost children and their descendants of the right node
|
|
|
|
// join them up. Can you say that three times fast?
|
1999-08-31 13:55:18 +00:00
|
|
|
|
1999-05-17 12:22:31 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> leftNodeToJoin = do_QueryInterface(aLeftNode);
|
|
|
|
nsCOMPtr<nsIDOMNode> rightNodeToJoin = do_QueryInterface(aRightNode);
|
1999-08-31 13:55:18 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> parentNode,tmp;
|
1999-05-17 12:22:31 +00:00
|
|
|
nsresult res = NS_OK;
|
|
|
|
|
|
|
|
rightNodeToJoin->GetParentNode(getter_AddRefs(parentNode));
|
|
|
|
|
|
|
|
while (leftNodeToJoin && rightNodeToJoin && parentNode &&
|
|
|
|
NodesSameType(leftNodeToJoin, rightNodeToJoin))
|
|
|
|
{
|
1999-08-31 13:55:18 +00:00
|
|
|
// adjust out params
|
|
|
|
PRUint32 length;
|
|
|
|
if (IsTextNode(leftNodeToJoin))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
|
|
|
nodeAsText = do_QueryInterface(leftNodeToJoin);
|
|
|
|
nodeAsText->GetLength(&length);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
res = GetLengthOfDOMNode(leftNodeToJoin, length);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
1999-08-31 13:55:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*aOutJoinNode = rightNodeToJoin;
|
|
|
|
*outOffset = length;
|
1999-05-17 12:22:31 +00:00
|
|
|
|
1999-08-31 13:55:18 +00:00
|
|
|
// do the join
|
|
|
|
res = JoinNodes(leftNodeToJoin, rightNodeToJoin, parentNode);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
1999-05-17 12:22:31 +00:00
|
|
|
|
|
|
|
if (IsTextNode(parentNode)) // we've joined all the way down to text nodes, we're done!
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// get new left and right nodes, and begin anew
|
1999-08-31 13:55:18 +00:00
|
|
|
parentNode = rightNodeToJoin;
|
|
|
|
leftNodeToJoin = GetChildAt(parentNode, length-1);
|
|
|
|
rightNodeToJoin = GetChildAt(parentNode, length);
|
|
|
|
|
|
|
|
// skip over non-editable nodes
|
|
|
|
while (leftNodeToJoin && !IsEditable(leftNodeToJoin))
|
|
|
|
{
|
|
|
|
leftNodeToJoin->GetPreviousSibling(getter_AddRefs(tmp));
|
|
|
|
leftNodeToJoin = tmp;
|
|
|
|
}
|
|
|
|
if (!leftNodeToJoin) break;
|
|
|
|
|
|
|
|
while (rightNodeToJoin && !IsEditable(rightNodeToJoin))
|
|
|
|
{
|
|
|
|
rightNodeToJoin->GetNextSibling(getter_AddRefs(tmp));
|
|
|
|
rightNodeToJoin = tmp;
|
|
|
|
}
|
|
|
|
if (!rightNodeToJoin) break;
|
1999-05-17 12:22:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
1999-06-14 20:02:46 +00:00
|
|
|
nsresult nsEditor::BeginUpdateViewBatch()
|
|
|
|
{
|
2003-04-04 20:50:25 +00:00
|
|
|
NS_PRECONDITION(mUpdateCount >= 0, "bad state");
|
1999-06-14 20:02:46 +00:00
|
|
|
|
|
|
|
|
2003-04-04 20:50:25 +00:00
|
|
|
if (0 == mUpdateCount)
|
1999-06-14 20:02:46 +00:00
|
|
|
{
|
2003-04-04 20:50:25 +00:00
|
|
|
// Turn off selection updates and notifications.
|
|
|
|
|
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
|
|
GetSelection(getter_AddRefs(selection));
|
|
|
|
|
|
|
|
if (selection)
|
1999-06-14 20:02:46 +00:00
|
|
|
{
|
2003-04-04 20:50:25 +00:00
|
|
|
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(selection));
|
|
|
|
selPrivate->StartBatchChanges();
|
1999-06-14 20:02:46 +00:00
|
|
|
}
|
2003-04-04 20:50:25 +00:00
|
|
|
|
|
|
|
// Turn off view updating.
|
2010-05-24 02:13:00 +00:00
|
|
|
nsCOMPtr<nsIPresShell> ps;
|
|
|
|
GetPresShell(getter_AddRefs(ps));
|
|
|
|
if (ps) {
|
|
|
|
nsCOMPtr<nsIViewManager> viewManager = ps->GetViewManager();
|
|
|
|
if (viewManager) {
|
|
|
|
mBatch.BeginUpdateViewBatch(viewManager);
|
|
|
|
}
|
|
|
|
}
|
1999-06-14 20:02:46 +00:00
|
|
|
}
|
|
|
|
|
2003-04-04 20:50:25 +00:00
|
|
|
mUpdateCount++;
|
|
|
|
|
1999-06-14 20:02:46 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult nsEditor::EndUpdateViewBatch()
|
|
|
|
{
|
2003-04-04 20:50:25 +00:00
|
|
|
NS_PRECONDITION(mUpdateCount > 0, "bad state");
|
1999-09-14 23:44:05 +00:00
|
|
|
|
2003-04-04 20:50:25 +00:00
|
|
|
if (mUpdateCount <= 0)
|
|
|
|
{
|
|
|
|
mUpdateCount = 0;
|
2001-10-17 14:33:50 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
2003-04-04 20:50:25 +00:00
|
|
|
}
|
2001-10-17 14:33:50 +00:00
|
|
|
|
2003-04-04 20:50:25 +00:00
|
|
|
mUpdateCount--;
|
2001-10-17 14:33:50 +00:00
|
|
|
|
2003-04-04 20:50:25 +00:00
|
|
|
if (0 == mUpdateCount)
|
1999-06-14 20:02:46 +00:00
|
|
|
{
|
2006-04-27 22:34:07 +00:00
|
|
|
// Hide the caret with an StCaretHider. By the time it goes out
|
|
|
|
// of scope and tries to show the caret, reflow and selection changed
|
|
|
|
// notifications should've happened so the caret should have enough info
|
|
|
|
// to draw at the correct position.
|
|
|
|
|
2008-07-16 10:52:01 +00:00
|
|
|
nsRefPtr<nsCaret> caret;
|
2003-04-04 20:50:25 +00:00
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
|
|
GetPresShell(getter_AddRefs(presShell));
|
2000-07-14 20:26:09 +00:00
|
|
|
|
2006-04-27 22:34:07 +00:00
|
|
|
if (presShell)
|
2010-03-31 12:39:31 +00:00
|
|
|
caret = presShell->GetCaret();
|
2006-04-27 22:34:07 +00:00
|
|
|
|
|
|
|
StCaretHider caretHider(caret);
|
2010-03-31 12:39:31 +00:00
|
|
|
|
2003-04-04 20:50:25 +00:00
|
|
|
PRUint32 flags = 0;
|
2000-07-14 20:26:09 +00:00
|
|
|
|
2003-04-04 20:50:25 +00:00
|
|
|
GetFlags(&flags);
|
2003-04-02 05:48:09 +00:00
|
|
|
|
2003-04-04 20:50:25 +00:00
|
|
|
// Turn view updating back on.
|
2010-05-24 02:13:00 +00:00
|
|
|
nsCOMPtr<nsIViewManager> viewManager;
|
|
|
|
if (presShell)
|
|
|
|
viewManager = presShell->GetViewManager();
|
|
|
|
if (viewManager)
|
2003-04-04 20:50:25 +00:00
|
|
|
{
|
2000-07-14 20:26:09 +00:00
|
|
|
PRUint32 updateFlag = NS_VMREFRESH_IMMEDIATE;
|
|
|
|
|
2005-01-20 03:39:09 +00:00
|
|
|
// If we're doing async updates, use NS_VMREFRESH_DEFERRED here, so that
|
|
|
|
// the reflows we caused will get processed before the invalidates.
|
2007-08-29 18:57:29 +00:00
|
|
|
if (flags & nsIPlaintextEditor::eEditorUseAsyncUpdatesMask) {
|
2005-01-20 03:39:09 +00:00
|
|
|
updateFlag = NS_VMREFRESH_DEFERRED;
|
2009-02-19 07:52:54 +00:00
|
|
|
} else if (presShell) {
|
2007-08-29 18:57:29 +00:00
|
|
|
// Flush out layout. Need to do this because if we have no invalidates
|
|
|
|
// to flush the viewmanager code won't flush our reflow here, and we
|
|
|
|
// have selection code that does sync caret scrolling in this case.
|
|
|
|
presShell->FlushPendingNotifications(Flush_Layout);
|
|
|
|
}
|
2008-01-26 23:59:50 +00:00
|
|
|
mBatch.EndUpdateViewBatch(updateFlag);
|
1999-06-14 20:02:46 +00:00
|
|
|
}
|
|
|
|
|
2003-04-04 20:50:25 +00:00
|
|
|
// Turn selection updating and notifications back on.
|
|
|
|
|
|
|
|
nsCOMPtr<nsISelection>selection;
|
|
|
|
GetSelection(getter_AddRefs(selection));
|
|
|
|
|
|
|
|
if (selection) {
|
|
|
|
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(selection));
|
|
|
|
selPrivate->EndBatchChanges();
|
|
|
|
}
|
2003-04-02 05:48:09 +00:00
|
|
|
}
|
|
|
|
|
1999-06-14 20:02:46 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-01-04 03:09:41 +00:00
|
|
|
PRBool
|
|
|
|
nsEditor::GetShouldTxnSetSelection()
|
|
|
|
{
|
|
|
|
return mShouldTxnSetSelection;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
2000-03-24 00:26:47 +00:00
|
|
|
#pragma mark protected nsEditor methods
|
1999-08-09 01:37:50 +00:00
|
|
|
#pragma mark -
|
|
|
|
#endif
|
1999-06-08 06:04:51 +00:00
|
|
|
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_IMETHODIMP
|
2000-08-14 02:39:37 +00:00
|
|
|
nsEditor::DeleteSelectionImpl(nsIEditor::EDirection aAction)
|
1999-06-08 06:04:51 +00:00
|
|
|
{
|
2000-09-14 11:45:01 +00:00
|
|
|
nsCOMPtr<nsISelection>selection;
|
2003-06-30 18:55:06 +00:00
|
|
|
nsresult res = GetSelection(getter_AddRefs(selection));
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2007-07-02 14:01:27 +00:00
|
|
|
nsRefPtr<EditAggregateTxn> txn;
|
2006-08-30 14:17:05 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> deleteNode;
|
2006-10-05 13:20:30 +00:00
|
|
|
PRInt32 deleteCharOffset = 0, deleteCharLength = 0;
|
2007-07-02 14:01:27 +00:00
|
|
|
res = CreateTxnForDeleteSelection(aAction, getter_AddRefs(txn),
|
|
|
|
getter_AddRefs(deleteNode),
|
|
|
|
&deleteCharOffset, &deleteCharLength);
|
2006-10-05 13:20:30 +00:00
|
|
|
nsCOMPtr<nsIDOMCharacterData> deleteCharData(do_QueryInterface(deleteNode));
|
2006-08-30 14:17:05 +00:00
|
|
|
|
1999-12-07 08:30:19 +00:00
|
|
|
if (NS_SUCCEEDED(res))
|
|
|
|
{
|
2006-10-05 13:20:30 +00:00
|
|
|
nsAutoRules beginRulesSniffing(this, kOpDeleteSelection, aAction);
|
|
|
|
PRInt32 i;
|
2006-08-30 14:17:05 +00:00
|
|
|
// Notify nsIEditActionListener::WillDelete[Selection|Text|Node]
|
2006-10-09 15:41:26 +00:00
|
|
|
if (!deleteNode)
|
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->WillDeleteSelection(selection);
|
|
|
|
else if (deleteCharData)
|
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->WillDeleteText(deleteCharData, deleteCharOffset, 1);
|
|
|
|
else
|
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->WillDeleteNode(deleteNode);
|
1999-12-07 08:30:19 +00:00
|
|
|
|
2006-08-30 14:17:05 +00:00
|
|
|
// Delete the specified amount
|
2003-04-04 20:50:25 +00:00
|
|
|
res = DoTransaction(txn);
|
1999-12-07 08:30:19 +00:00
|
|
|
|
2006-08-30 14:17:05 +00:00
|
|
|
// Notify nsIEditActionListener::DidDelete[Selection|Text|Node]
|
2006-10-09 15:41:26 +00:00
|
|
|
if (!deleteNode)
|
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->DidDeleteSelection(selection);
|
|
|
|
else if (deleteCharData)
|
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->DidDeleteText(deleteCharData, deleteCharOffset, 1, res);
|
|
|
|
else
|
|
|
|
for (i = 0; i < mActionListeners.Count(); i++)
|
|
|
|
mActionListeners[i]->DidDeleteNode(deleteNode, res);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
|
1999-12-07 08:30:19 +00:00
|
|
|
return res;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
|
2001-01-28 20:13:07 +00:00
|
|
|
// XXX: error handling in this routine needs to be cleaned up!
|
|
|
|
NS_IMETHODIMP
|
2002-03-23 22:16:54 +00:00
|
|
|
nsEditor::DeleteSelectionAndCreateNode(const nsAString& aTag,
|
2001-01-28 20:13:07 +00:00
|
|
|
nsIDOMNode ** aNewNode)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> parentSelectedNode;
|
|
|
|
PRInt32 offsetOfNewNode;
|
|
|
|
nsresult result = DeleteSelectionAndPrepareToCreateNode(parentSelectedNode,
|
|
|
|
offsetOfNewNode);
|
2010-06-17 20:44:35 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2001-01-28 20:13:07 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> newNode;
|
|
|
|
result = CreateNode(aTag, parentSelectedNode, offsetOfNewNode,
|
|
|
|
getter_AddRefs(newNode));
|
|
|
|
// XXX: ERROR_HANDLING check result, and make sure aNewNode is set correctly in success/failure cases
|
|
|
|
*aNewNode = newNode;
|
|
|
|
NS_IF_ADDREF(*aNewNode);
|
|
|
|
|
|
|
|
// we want the selection to be just after the new node
|
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
|
|
result = GetSelection(getter_AddRefs(selection));
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
|
2003-06-30 18:55:06 +00:00
|
|
|
return selection->Collapse(parentSelectedNode, offsetOfNewNode+1);
|
2001-01-28 20:13:07 +00:00
|
|
|
}
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
|
|
|
|
/* Non-interface, protected methods */
|
|
|
|
|
2002-12-22 01:51:14 +00:00
|
|
|
nsresult
|
|
|
|
nsEditor::GetIMEBufferLength(PRInt32* length)
|
|
|
|
{
|
|
|
|
*length = mIMEBufferLength;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsEditor::SetIsIMEComposing(){
|
|
|
|
// We set mIsIMEComposing according to mIMETextRangeList.
|
|
|
|
nsCOMPtr<nsIPrivateTextRange> rangePtr;
|
|
|
|
PRUint16 listlen, type;
|
|
|
|
|
|
|
|
mIsIMEComposing = PR_FALSE;
|
2008-10-09 23:30:48 +00:00
|
|
|
listlen = mIMETextRangeList->GetLength();
|
2002-12-22 01:51:14 +00:00
|
|
|
|
|
|
|
for (PRUint16 i = 0; i < listlen; i++)
|
|
|
|
{
|
2008-10-09 23:30:48 +00:00
|
|
|
rangePtr = mIMETextRangeList->Item(i);
|
|
|
|
if (!rangePtr) continue;
|
|
|
|
nsresult result = rangePtr->GetRangeType(&type);
|
2002-12-22 01:51:14 +00:00
|
|
|
if (NS_FAILED(result)) continue;
|
|
|
|
if ( type == nsIPrivateTextRange::TEXTRANGE_RAWINPUT ||
|
|
|
|
type == nsIPrivateTextRange::TEXTRANGE_CONVERTEDTEXT ||
|
|
|
|
type == nsIPrivateTextRange::TEXTRANGE_SELECTEDRAWTEXT ||
|
|
|
|
type == nsIPrivateTextRange::TEXTRANGE_SELECTEDCONVERTEDTEXT )
|
|
|
|
{
|
|
|
|
mIsIMEComposing = PR_TRUE;
|
|
|
|
#ifdef DEBUG_IME
|
|
|
|
printf("nsEditor::mIsIMEComposing = PR_TRUE\n");
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsEditor::IsIMEComposing() {
|
|
|
|
return mIsIMEComposing;
|
|
|
|
}
|
|
|
|
|
2001-01-28 20:13:07 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNode> &parentSelectedNode, PRInt32& offsetOfNewNode)
|
|
|
|
{
|
|
|
|
nsresult result=NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
|
|
result = GetSelection(getter_AddRefs(selection));
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
|
2001-01-28 20:13:07 +00:00
|
|
|
|
|
|
|
PRBool collapsed;
|
|
|
|
result = selection->GetIsCollapsed(&collapsed);
|
|
|
|
if (NS_SUCCEEDED(result) && !collapsed)
|
|
|
|
{
|
|
|
|
result = DeleteSelection(nsIEditor::eNone);
|
|
|
|
if (NS_FAILED(result)) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
// get the new selection
|
|
|
|
result = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(result)) {
|
|
|
|
return result;
|
|
|
|
}
|
2010-07-12 04:23:25 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> selectedNode;
|
|
|
|
selection->GetAnchorNode(getter_AddRefs(selectedNode));
|
2001-01-28 20:13:07 +00:00
|
|
|
// no selection is ok.
|
|
|
|
// if there is a selection, it must be collapsed
|
2010-07-12 04:23:25 +00:00
|
|
|
if (selectedNode)
|
2001-01-28 20:13:07 +00:00
|
|
|
{
|
2010-07-12 04:23:25 +00:00
|
|
|
PRBool testCollapsed = PR_FALSE;
|
|
|
|
selection->GetIsCollapsed(&testCollapsed);
|
|
|
|
if (!testCollapsed) {
|
|
|
|
result = selection->CollapseToEnd();
|
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
|
|
|
}
|
2001-01-28 20:13:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// split the selected node
|
|
|
|
PRInt32 offsetOfSelectedNode;
|
|
|
|
result = selection->GetAnchorNode(getter_AddRefs(parentSelectedNode));
|
|
|
|
if (NS_SUCCEEDED(result) && NS_SUCCEEDED(selection->GetAnchorOffset(&offsetOfSelectedNode)) && parentSelectedNode)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> selectedNode;
|
|
|
|
PRUint32 selectedNodeContentCount=0;
|
|
|
|
nsCOMPtr<nsIDOMCharacterData>selectedParentNodeAsText;
|
|
|
|
selectedParentNodeAsText = do_QueryInterface(parentSelectedNode);
|
|
|
|
|
|
|
|
offsetOfNewNode = offsetOfSelectedNode;
|
|
|
|
|
2005-11-25 08:16:51 +00:00
|
|
|
/* if the selection is a text node, split the text node if necessary
|
2001-01-28 20:13:07 +00:00
|
|
|
and compute where to put the new node
|
|
|
|
*/
|
|
|
|
if (selectedParentNodeAsText)
|
|
|
|
{
|
|
|
|
PRInt32 indexOfTextNodeInParent;
|
|
|
|
selectedNode = do_QueryInterface(parentSelectedNode);
|
|
|
|
selectedNode->GetParentNode(getter_AddRefs(parentSelectedNode));
|
|
|
|
selectedParentNodeAsText->GetLength(&selectedNodeContentCount);
|
|
|
|
GetChildOffset(selectedNode, parentSelectedNode, indexOfTextNodeInParent);
|
|
|
|
|
|
|
|
if ((offsetOfSelectedNode!=0) && (((PRUint32)offsetOfSelectedNode)!=selectedNodeContentCount))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> newSiblingNode;
|
|
|
|
result = SplitNode(selectedNode, offsetOfSelectedNode, getter_AddRefs(newSiblingNode));
|
|
|
|
// now get the node's offset in it's parent, and insert the new tag there
|
|
|
|
if (NS_SUCCEEDED(result)) {
|
|
|
|
result = GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // determine where to insert the new node
|
|
|
|
if (0==offsetOfSelectedNode) {
|
|
|
|
offsetOfNewNode = indexOfTextNodeInParent; // insert new node as previous sibling to selection parent
|
|
|
|
}
|
|
|
|
else { // insert new node as last child
|
|
|
|
GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
|
|
|
|
offsetOfNewNode++; // offsets are 0-based, and we need the index of the new node
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Here's where the new node was inserted
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
else {
|
|
|
|
printf("InsertLineBreak into an empty document is not yet supported\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::DoAfterDoTransaction(nsITransaction *aTxn)
|
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
|
|
|
PRBool isTransientTransaction;
|
|
|
|
rv = aTxn->GetIsTransient(&isTransientTransaction);
|
2010-06-17 20:44:35 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
1999-08-09 01:37:50 +00:00
|
|
|
|
|
|
|
if (!isTransientTransaction)
|
|
|
|
{
|
|
|
|
// we need to deal here with the case where the user saved after some
|
|
|
|
// edits, then undid one or more times. Then, the undo count is -ve,
|
|
|
|
// but we can't let a do take it back to zero. So we flip it up to
|
|
|
|
// a +ve number.
|
|
|
|
PRInt32 modCount;
|
2001-12-10 15:23:11 +00:00
|
|
|
GetModificationCount(&modCount);
|
1999-08-09 01:37:50 +00:00
|
|
|
if (modCount < 0)
|
|
|
|
modCount = -modCount;
|
|
|
|
|
2001-12-10 15:23:11 +00:00
|
|
|
rv = IncrementModificationCount(1); // don't count transient transactions
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::DoAfterUndoTransaction()
|
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
2001-12-10 15:23:11 +00:00
|
|
|
rv = IncrementModificationCount(-1); // all undoable transactions are non-transient
|
1999-08-09 01:37:50 +00:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::DoAfterRedoTransaction()
|
|
|
|
{
|
2001-12-10 15:23:11 +00:00
|
|
|
return IncrementModificationCount(1); // all redoable transactions are non-transient
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::CreateTxnForSetAttribute(nsIDOMElement *aElement,
|
2002-03-23 22:16:54 +00:00
|
|
|
const nsAString& aAttribute,
|
|
|
|
const nsAString& aValue,
|
1999-08-09 01:37:50 +00:00
|
|
|
ChangeAttributeTxn ** aTxn)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
|
2009-04-24 22:45:34 +00:00
|
|
|
|
|
|
|
*aTxn = new ChangeAttributeTxn();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(*aTxn, NS_ERROR_OUT_OF_MEMORY);
|
2009-04-24 22:45:34 +00:00
|
|
|
NS_ADDREF(*aTxn);
|
|
|
|
return (*aTxn)->Init(this, aElement, aAttribute, aValue, PR_FALSE);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::CreateTxnForRemoveAttribute(nsIDOMElement *aElement,
|
2002-03-23 22:16:54 +00:00
|
|
|
const nsAString& aAttribute,
|
1999-08-09 01:37:50 +00:00
|
|
|
ChangeAttributeTxn ** aTxn)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
|
2009-04-24 22:45:34 +00:00
|
|
|
|
|
|
|
*aTxn = new ChangeAttributeTxn();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(*aTxn, NS_ERROR_OUT_OF_MEMORY);
|
2009-04-24 22:45:34 +00:00
|
|
|
NS_ADDREF(*aTxn);
|
|
|
|
|
|
|
|
return (*aTxn)->Init(this, aElement, aAttribute, EmptyString(), PR_TRUE);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-03-23 22:16:54 +00:00
|
|
|
NS_IMETHODIMP nsEditor::CreateTxnForCreateElement(const nsAString& aTag,
|
1999-08-09 01:37:50 +00:00
|
|
|
nsIDOMNode *aParent,
|
|
|
|
PRInt32 aPosition,
|
|
|
|
CreateElementTxn ** aTxn)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aParent, NS_ERROR_NULL_POINTER);
|
2009-04-24 22:45:34 +00:00
|
|
|
|
|
|
|
*aTxn = new CreateElementTxn();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(*aTxn, NS_ERROR_OUT_OF_MEMORY);
|
2009-04-24 22:45:34 +00:00
|
|
|
NS_ADDREF(*aTxn);
|
|
|
|
|
|
|
|
return (*aTxn)->Init(this, aTag, aParent, aPosition);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsEditor::CreateTxnForInsertElement(nsIDOMNode * aNode,
|
|
|
|
nsIDOMNode * aParent,
|
|
|
|
PRInt32 aPosition,
|
|
|
|
InsertElementTxn ** aTxn)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aNode && aParent, NS_ERROR_NULL_POINTER);
|
2009-04-24 22:45:34 +00:00
|
|
|
|
|
|
|
*aTxn = new InsertElementTxn();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(*aTxn, NS_ERROR_OUT_OF_MEMORY);
|
2009-04-24 22:45:34 +00:00
|
|
|
NS_ADDREF(*aTxn);
|
|
|
|
|
|
|
|
return (*aTxn)->Init(aNode, aParent, aPosition, this);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsEditor::CreateTxnForDeleteElement(nsIDOMNode * aElement,
|
|
|
|
DeleteElementTxn ** aTxn)
|
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
|
2009-04-24 22:45:34 +00:00
|
|
|
|
|
|
|
*aTxn = new DeleteElementTxn();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(*aTxn, NS_ERROR_OUT_OF_MEMORY);
|
2009-04-24 22:45:34 +00:00
|
|
|
NS_ADDREF(*aTxn);
|
|
|
|
|
|
|
|
return (*aTxn)->Init(this, aElement, &mRangeUpdater);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2002-03-23 22:16:54 +00:00
|
|
|
nsEditor::CreateTxnForIMEText(const nsAString& aStringToInsert,
|
1999-08-09 01:37:50 +00:00
|
|
|
IMETextTxn ** aTxn)
|
|
|
|
{
|
1999-10-18 14:48:41 +00:00
|
|
|
NS_ASSERTION(aTxn, "illegal value- null ptr- aTxn");
|
2000-01-04 03:09:41 +00:00
|
|
|
|
2009-04-24 22:45:34 +00:00
|
|
|
*aTxn = new IMETextTxn();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(*aTxn, NS_ERROR_OUT_OF_MEMORY);
|
2009-04-24 22:45:34 +00:00
|
|
|
NS_ADDREF(*aTxn);
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2009-04-24 22:45:34 +00:00
|
|
|
return (*aTxn)->Init(mIMETextNode, mIMETextOffset, mIMEBufferLength,
|
|
|
|
mIMETextRangeList, aStringToInsert, mSelConWeak);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2010-05-11 20:41:47 +00:00
|
|
|
nsEditor::CreateTxnForAddStyleSheet(nsCSSStyleSheet* aSheet, AddStyleSheetTxn* *aTxn)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
2009-04-24 22:45:34 +00:00
|
|
|
*aTxn = new AddStyleSheetTxn();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE( *aTxn, NS_ERROR_OUT_OF_MEMORY);
|
2009-04-24 22:45:34 +00:00
|
|
|
NS_ADDREF(*aTxn);
|
1999-08-09 01:37:50 +00:00
|
|
|
|
|
|
|
return (*aTxn)->Init(this, aSheet);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2010-05-11 20:41:47 +00:00
|
|
|
nsEditor::CreateTxnForRemoveStyleSheet(nsCSSStyleSheet* aSheet, RemoveStyleSheetTxn* *aTxn)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
2009-04-24 22:45:34 +00:00
|
|
|
*aTxn = new RemoveStyleSheetTxn();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE( *aTxn, NS_ERROR_OUT_OF_MEMORY);
|
2009-04-24 22:45:34 +00:00
|
|
|
NS_ADDREF(*aTxn);
|
1999-08-09 01:37:50 +00:00
|
|
|
|
|
|
|
return (*aTxn)->Init(this, aSheet);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-12-07 08:30:19 +00:00
|
|
|
nsEditor::CreateTxnForDeleteSelection(nsIEditor::EDirection aAction,
|
2006-10-05 13:20:30 +00:00
|
|
|
EditAggregateTxn ** aTxn,
|
|
|
|
nsIDOMNode ** aNode,
|
|
|
|
PRInt32 *aOffset,
|
|
|
|
PRInt32 *aLength)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(aTxn, NS_ERROR_NULL_POINTER);
|
1999-08-09 01:37:50 +00:00
|
|
|
*aTxn = nsnull;
|
|
|
|
|
2000-05-08 04:01:26 +00:00
|
|
|
nsCOMPtr<nsISelectionController> selCon = do_QueryReferent(mSelConWeak);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
|
2003-06-30 18:55:06 +00:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
|
|
nsresult result = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
|
|
|
|
getter_AddRefs(selection));
|
1999-08-09 01:37:50 +00:00
|
|
|
if ((NS_SUCCEEDED(result)) && selection)
|
|
|
|
{
|
|
|
|
// Check whether the selection is collapsed and we should do nothing:
|
|
|
|
PRBool isCollapsed;
|
|
|
|
result = (selection->GetIsCollapsed(&isCollapsed));
|
1999-12-07 08:30:19 +00:00
|
|
|
if (NS_SUCCEEDED(result) && isCollapsed && aAction == eNone)
|
1999-08-09 01:37:50 +00:00
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
// allocate the out-param transaction
|
2009-04-24 22:45:34 +00:00
|
|
|
*aTxn = new EditAggregateTxn();
|
|
|
|
if (!*aTxn) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
2009-04-24 22:45:34 +00:00
|
|
|
NS_ADDREF(*aTxn);
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2000-09-14 11:45:01 +00:00
|
|
|
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(selection));
|
2003-06-30 18:55:06 +00:00
|
|
|
nsCOMPtr<nsIEnumerator> enumerator;
|
2000-09-14 11:45:01 +00:00
|
|
|
result = selPrivate->GetEnumerator(getter_AddRefs(enumerator));
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_SUCCEEDED(result) && enumerator)
|
|
|
|
{
|
|
|
|
for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next())
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupports> currentItem;
|
|
|
|
result = enumerator->CurrentItem(getter_AddRefs(currentItem));
|
|
|
|
if ((NS_SUCCEEDED(result)) && (currentItem))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
|
2000-08-24 03:54:30 +00:00
|
|
|
range->GetCollapsed(&isCollapsed);
|
2003-06-30 18:55:06 +00:00
|
|
|
if (!isCollapsed)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
2009-04-24 22:45:34 +00:00
|
|
|
nsRefPtr<DeleteRangeTxn> txn = new DeleteRangeTxn();
|
|
|
|
if (txn)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
2002-11-10 15:11:08 +00:00
|
|
|
txn->Init(this, range, &mRangeUpdater);
|
1999-08-09 01:37:50 +00:00
|
|
|
(*aTxn)->AppendChild(txn);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result = NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2007-08-25 12:37:38 +00:00
|
|
|
// Same with range as with selection; if it is collapsed and action
|
|
|
|
// is eNone, do nothing.
|
|
|
|
else if (aAction != eNone)
|
1999-08-09 01:37:50 +00:00
|
|
|
{ // we have an insertion point. delete the thing in front of it or behind it, depending on aAction
|
2006-10-05 13:20:30 +00:00
|
|
|
result = CreateTxnForDeleteInsertionPoint(range, aAction, *aTxn, aNode, aOffset, aLength);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we didn't build the transaction correctly, destroy the out-param transaction so we don't leak it.
|
|
|
|
if (NS_FAILED(result))
|
|
|
|
{
|
|
|
|
NS_IF_RELEASE(*aTxn);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2006-04-04 00:57:55 +00:00
|
|
|
nsresult
|
|
|
|
nsEditor::CreateTxnForDeleteCharacter(nsIDOMCharacterData *aData,
|
|
|
|
PRUint32 aOffset,
|
|
|
|
nsIEditor::EDirection aDirection,
|
|
|
|
DeleteTextTxn **aTxn)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aDirection == eNext || aDirection == ePrevious,
|
|
|
|
"invalid direction");
|
|
|
|
nsAutoString data;
|
|
|
|
aData->GetData(data);
|
|
|
|
PRUint32 segOffset, segLength = 1;
|
|
|
|
if (aDirection == eNext) {
|
|
|
|
segOffset = aOffset;
|
2010-06-16 16:33:13 +00:00
|
|
|
if (segOffset + 1 < data.Length() &&
|
|
|
|
NS_IS_HIGH_SURROGATE(data[segOffset]) &&
|
2006-12-21 07:03:23 +00:00
|
|
|
NS_IS_LOW_SURROGATE(data[segOffset+1])) {
|
2006-04-04 00:57:55 +00:00
|
|
|
// delete both halves of the surrogate pair
|
|
|
|
++segLength;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
segOffset = aOffset - 1;
|
2010-06-16 16:33:13 +00:00
|
|
|
if (segOffset > 1 &&
|
|
|
|
NS_IS_LOW_SURROGATE(data[segOffset]) &&
|
2006-12-21 07:03:23 +00:00
|
|
|
NS_IS_HIGH_SURROGATE(data[segOffset-1])) {
|
2006-04-04 00:57:55 +00:00
|
|
|
++segLength;
|
|
|
|
--segOffset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return CreateTxnForDeleteText(aData, segOffset, segLength, aTxn);
|
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
|
|
|
|
//XXX: currently, this doesn't handle edge conditions because GetNext/GetPrior are not implemented
|
|
|
|
NS_IMETHODIMP
|
2002-11-10 15:11:08 +00:00
|
|
|
nsEditor::CreateTxnForDeleteInsertionPoint(nsIDOMRange *aRange,
|
|
|
|
nsIEditor::EDirection aAction,
|
2006-10-05 13:20:30 +00:00
|
|
|
EditAggregateTxn *aTxn,
|
|
|
|
nsIDOMNode **aNode,
|
|
|
|
PRInt32 *aOffset,
|
|
|
|
PRInt32 *aLength)
|
1999-08-09 01:37:50 +00:00
|
|
|
{
|
2006-04-04 00:57:55 +00:00
|
|
|
NS_ASSERTION(aAction == eNext || aAction == ePrevious, "invalid action");
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
// get the node and offset of the insertion point
|
2003-06-30 18:55:06 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
2000-08-24 03:54:30 +00:00
|
|
|
nsresult result = aRange->GetStartContainer(getter_AddRefs(node));
|
2010-06-17 20:44:35 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2003-06-30 18:55:06 +00:00
|
|
|
|
|
|
|
PRInt32 offset;
|
1999-08-09 01:37:50 +00:00
|
|
|
result = aRange->GetStartOffset(&offset);
|
2010-06-17 20:44:35 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
1999-08-09 01:37:50 +00:00
|
|
|
|
|
|
|
// determine if the insertion point is at the beginning, middle, or end of the node
|
2003-06-30 18:55:06 +00:00
|
|
|
nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(node);
|
1999-08-09 01:37:50 +00:00
|
|
|
|
2001-09-10 14:46:57 +00:00
|
|
|
PRUint32 count=0;
|
|
|
|
|
1999-08-09 01:37:50 +00:00
|
|
|
if (nodeAsText)
|
|
|
|
nodeAsText->GetLength(&count);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// get the child list and count
|
|
|
|
nsCOMPtr<nsIDOMNodeList>childList;
|
|
|
|
result = node->GetChildNodes(getter_AddRefs(childList));
|
|
|
|
if ((NS_SUCCEEDED(result)) && childList)
|
|
|
|
childList->GetLength(&count);
|
|
|
|
}
|
2001-09-10 14:46:57 +00:00
|
|
|
|
2003-06-30 18:55:06 +00:00
|
|
|
PRBool isFirst = (0 == offset);
|
|
|
|
PRBool isLast = (count == (PRUint32)offset);
|
2001-09-10 14:46:57 +00:00
|
|
|
|
2002-11-10 15:11:08 +00:00
|
|
|
// XXX: if isFirst && isLast, then we'll need to delete the node
|
|
|
|
// as well as the 1 child
|
1999-08-09 01:37:50 +00:00
|
|
|
|
|
|
|
// build a transaction for deleting the appropriate data
|
|
|
|
// XXX: this has to come from rule section
|
1999-12-07 08:30:19 +00:00
|
|
|
if ((ePrevious==aAction) && (PR_TRUE==isFirst))
|
1999-08-09 01:37:50 +00:00
|
|
|
{ // we're backspacing from the beginning of the node. Delete the first thing to our left
|
|
|
|
nsCOMPtr<nsIDOMNode> priorNode;
|
2001-08-22 05:32:44 +00:00
|
|
|
result = GetPriorNode(node, PR_TRUE, address_of(priorNode));
|
1999-08-09 01:37:50 +00:00
|
|
|
if ((NS_SUCCEEDED(result)) && priorNode)
|
|
|
|
{ // there is a priorNode, so delete it's last child (if text content, delete the last char.)
|
|
|
|
// if it has no children, delete it
|
2003-06-30 18:55:06 +00:00
|
|
|
nsCOMPtr<nsIDOMCharacterData> priorNodeAsText = do_QueryInterface(priorNode);
|
1999-08-09 01:37:50 +00:00
|
|
|
if (priorNodeAsText)
|
|
|
|
{
|
|
|
|
PRUint32 length=0;
|
|
|
|
priorNodeAsText->GetLength(&length);
|
|
|
|
if (0<length)
|
|
|
|
{
|
|
|
|
DeleteTextTxn *txn;
|
2006-04-04 00:57:55 +00:00
|
|
|
result = CreateTxnForDeleteCharacter(priorNodeAsText, length,
|
|
|
|
ePrevious, &txn);
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_SUCCEEDED(result)) {
|
|
|
|
aTxn->AppendChild(txn);
|
2006-10-05 13:20:30 +00:00
|
|
|
NS_ADDREF(*aNode = priorNode);
|
|
|
|
*aOffset = txn->GetOffset();
|
|
|
|
*aLength = txn->GetNumCharsToDelete();
|
2000-03-23 01:14:49 +00:00
|
|
|
NS_RELEASE(txn);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // XXX: can you have an empty text node? If so, what do you do?
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("ERROR: found a text node with 0 characters\n");
|
1999-08-09 01:37:50 +00:00
|
|
|
result = NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // priorNode is not text, so tell it's parent to delete it
|
|
|
|
DeleteElementTxn *txn;
|
|
|
|
result = CreateTxnForDeleteElement(priorNode, &txn);
|
|
|
|
if (NS_SUCCEEDED(result)) {
|
|
|
|
aTxn->AppendChild(txn);
|
2000-03-23 01:14:49 +00:00
|
|
|
NS_RELEASE(txn);
|
2006-10-05 13:20:30 +00:00
|
|
|
NS_ADDREF(*aNode = priorNode);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-12-07 08:30:19 +00:00
|
|
|
else if ((nsIEditor::eNext==aAction) && (PR_TRUE==isLast))
|
1999-08-09 01:37:50 +00:00
|
|
|
{ // we're deleting from the end of the node. Delete the first thing to our right
|
|
|
|
nsCOMPtr<nsIDOMNode> nextNode;
|
2001-08-22 05:32:44 +00:00
|
|
|
result = GetNextNode(node, PR_TRUE, address_of(nextNode));
|
1999-08-09 01:37:50 +00:00
|
|
|
if ((NS_SUCCEEDED(result)) && nextNode)
|
2000-05-09 21:06:49 +00:00
|
|
|
{ // there is a nextNode, so delete it's first child (if text content, delete the first char.)
|
1999-08-09 01:37:50 +00:00
|
|
|
// if it has no children, delete it
|
2003-06-30 18:55:06 +00:00
|
|
|
nsCOMPtr<nsIDOMCharacterData> nextNodeAsText = do_QueryInterface(nextNode);
|
1999-08-09 01:37:50 +00:00
|
|
|
if (nextNodeAsText)
|
|
|
|
{
|
|
|
|
PRUint32 length=0;
|
|
|
|
nextNodeAsText->GetLength(&length);
|
|
|
|
if (0<length)
|
|
|
|
{
|
|
|
|
DeleteTextTxn *txn;
|
2006-04-04 00:57:55 +00:00
|
|
|
result = CreateTxnForDeleteCharacter(nextNodeAsText, 0, eNext, &txn);
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_SUCCEEDED(result)) {
|
|
|
|
aTxn->AppendChild(txn);
|
2006-10-05 13:20:30 +00:00
|
|
|
NS_ADDREF(*aNode = nextNode);
|
|
|
|
*aOffset = txn->GetOffset();
|
|
|
|
*aLength = txn->GetNumCharsToDelete();
|
2000-03-23 01:14:49 +00:00
|
|
|
NS_RELEASE(txn);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // XXX: can you have an empty text node? If so, what do you do?
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("ERROR: found a text node with 0 characters\n");
|
1999-08-09 01:37:50 +00:00
|
|
|
result = NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // nextNode is not text, so tell it's parent to delete it
|
|
|
|
DeleteElementTxn *txn;
|
|
|
|
result = CreateTxnForDeleteElement(nextNode, &txn);
|
|
|
|
if (NS_SUCCEEDED(result)) {
|
|
|
|
aTxn->AppendChild(txn);
|
2000-03-23 01:14:49 +00:00
|
|
|
NS_RELEASE(txn);
|
2006-10-05 13:20:30 +00:00
|
|
|
NS_ADDREF(*aNode = nextNode);
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (nodeAsText)
|
|
|
|
{ // we have text, so delete a char at the proper offset
|
2007-08-25 12:37:38 +00:00
|
|
|
nsRefPtr<DeleteTextTxn> txn;
|
|
|
|
result = CreateTxnForDeleteCharacter(nodeAsText, offset, aAction,
|
|
|
|
getter_AddRefs(txn));
|
1999-08-09 01:37:50 +00:00
|
|
|
if (NS_SUCCEEDED(result)) {
|
|
|
|
aTxn->AppendChild(txn);
|
2006-10-05 13:20:30 +00:00
|
|
|
NS_ADDREF(*aNode = node);
|
|
|
|
*aOffset = txn->GetOffset();
|
|
|
|
*aLength = txn->GetNumCharsToDelete();
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
1999-11-17 11:30:39 +00:00
|
|
|
{ // we're either deleting a node or some text, need to dig into the next/prev node to find out
|
1999-08-31 13:55:18 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> selectedNode;
|
1999-12-07 08:30:19 +00:00
|
|
|
if (ePrevious==aAction)
|
1999-08-31 13:55:18 +00:00
|
|
|
{
|
2001-08-22 05:32:44 +00:00
|
|
|
result = GetPriorNode(node, offset, PR_TRUE, address_of(selectedNode));
|
1999-08-31 13:55:18 +00:00
|
|
|
}
|
1999-12-07 08:30:19 +00:00
|
|
|
else if (eNext==aAction)
|
1999-08-31 13:55:18 +00:00
|
|
|
{
|
2001-08-22 05:32:44 +00:00
|
|
|
result = GetNextNode(node, offset, PR_TRUE, address_of(selectedNode));
|
1999-08-31 13:55:18 +00:00
|
|
|
}
|
1999-11-17 11:30:39 +00:00
|
|
|
if (NS_FAILED(result)) { return result; }
|
|
|
|
if (selectedNode)
|
1999-08-31 13:55:18 +00:00
|
|
|
{
|
2003-06-30 18:55:06 +00:00
|
|
|
nsCOMPtr<nsIDOMCharacterData> selectedNodeAsText =
|
|
|
|
do_QueryInterface(selectedNode);
|
1999-11-17 11:30:39 +00:00
|
|
|
if (selectedNodeAsText)
|
|
|
|
{ // we are deleting from a text node, so do a text deletion
|
2006-04-04 00:57:55 +00:00
|
|
|
PRUint32 position = 0; // default for forward delete
|
1999-12-07 08:30:19 +00:00
|
|
|
if (ePrevious==aAction)
|
1999-11-17 11:30:39 +00:00
|
|
|
{
|
2006-04-04 00:57:55 +00:00
|
|
|
selectedNodeAsText->GetLength(&position);
|
1999-11-17 11:30:39 +00:00
|
|
|
}
|
2007-08-25 12:37:38 +00:00
|
|
|
nsRefPtr<DeleteTextTxn> delTextTxn;
|
2006-04-04 00:57:55 +00:00
|
|
|
result = CreateTxnForDeleteCharacter(selectedNodeAsText, position,
|
2007-08-25 12:37:38 +00:00
|
|
|
aAction,
|
|
|
|
getter_AddRefs(delTextTxn));
|
1999-11-17 11:30:39 +00:00
|
|
|
if (NS_FAILED(result)) { return result; }
|
|
|
|
if (!delTextTxn) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
aTxn->AppendChild(delTextTxn);
|
2006-10-05 13:20:30 +00:00
|
|
|
NS_ADDREF(*aNode = selectedNode);
|
|
|
|
*aOffset = delTextTxn->GetOffset();
|
|
|
|
*aLength = delTextTxn->GetNumCharsToDelete();
|
1999-11-17 11:30:39 +00:00
|
|
|
}
|
|
|
|
else
|
1999-08-31 13:55:18 +00:00
|
|
|
{
|
2007-08-25 12:37:38 +00:00
|
|
|
nsRefPtr<DeleteElementTxn> delElementTxn;
|
|
|
|
result = CreateTxnForDeleteElement(selectedNode,
|
|
|
|
getter_AddRefs(delElementTxn));
|
1999-11-17 11:30:39 +00:00
|
|
|
if (NS_FAILED(result)) { return result; }
|
|
|
|
if (!delElementTxn) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
aTxn->AppendChild(delElementTxn);
|
2006-10-05 13:20:30 +00:00
|
|
|
NS_ADDREF(*aNode = selectedNode);
|
1999-08-31 13:55:18 +00:00
|
|
|
}
|
1999-08-09 01:37:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
1999-06-08 06:04:51 +00:00
|
|
|
}
|
|
|
|
|
2000-02-10 05:14:52 +00:00
|
|
|
nsresult
|
|
|
|
nsEditor::CreateRange(nsIDOMNode *aStartParent, PRInt32 aStartOffset,
|
|
|
|
nsIDOMNode *aEndParent, PRInt32 aEndOffset,
|
|
|
|
nsIDOMRange **aRange)
|
|
|
|
{
|
|
|
|
nsresult result;
|
2004-11-01 18:50:36 +00:00
|
|
|
result = CallCreateInstance("@mozilla.org/content/range;1", aRange);
|
2010-06-17 20:44:35 +00:00
|
|
|
NS_ENSURE_SUCCESS(result, result);
|
2000-02-10 05:14:52 +00:00
|
|
|
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(*aRange, NS_ERROR_NULL_POINTER);
|
2000-02-10 05:14:52 +00:00
|
|
|
|
|
|
|
result = (*aRange)->SetStart(aStartParent, aStartOffset);
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
result = (*aRange)->SetEnd(aEndParent, aEndOffset);
|
|
|
|
|
|
|
|
if (NS_FAILED(result))
|
|
|
|
{
|
|
|
|
NS_RELEASE((*aRange));
|
|
|
|
*aRange = 0;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsEditor::AppendNodeToSelectionAsRange(nsIDOMNode *aNode)
|
|
|
|
{
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
|
2000-09-14 11:45:01 +00:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
2000-02-10 05:14:52 +00:00
|
|
|
nsresult res = GetSelection(getter_AddRefs(selection));
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-02-10 05:14:52 +00:00
|
|
|
if(!selection) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> parentNode;
|
|
|
|
res = aNode->GetParentNode(getter_AddRefs(parentNode));
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(parentNode, NS_ERROR_NULL_POINTER);
|
2000-02-10 05:14:52 +00:00
|
|
|
|
|
|
|
PRInt32 offset;
|
|
|
|
res = GetChildOffset(aNode, parentNode, offset);
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2000-02-10 05:14:52 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMRange> range;
|
|
|
|
res = CreateRange(parentNode, offset, parentNode, offset+1, getter_AddRefs(range));
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(range, NS_ERROR_NULL_POINTER);
|
2000-02-10 05:14:52 +00:00
|
|
|
|
|
|
|
return selection->AddRange(range);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult nsEditor::ClearSelection()
|
|
|
|
{
|
2000-09-14 11:45:01 +00:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
2000-02-10 05:14:52 +00:00
|
|
|
nsresult res = nsEditor::GetSelection(getter_AddRefs(selection));
|
2010-06-17 19:27:24 +00:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
|
2000-09-14 11:45:01 +00:00
|
|
|
return selection->RemoveAllRanges();
|
2000-02-10 05:14:52 +00:00
|
|
|
}
|
|
|
|
|
2000-07-13 23:15:41 +00:00
|
|
|
nsresult
|
2002-03-23 22:16:54 +00:00
|
|
|
nsEditor::CreateHTMLContent(const nsAString& aTag, nsIContent** aContent)
|
2000-07-13 23:15:41 +00:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMDocument> tempDoc;
|
2004-06-25 12:26:02 +00:00
|
|
|
GetDocument(getter_AddRefs(tempDoc));
|
2000-07-13 23:15:41 +00:00
|
|
|
|
2003-06-30 18:55:06 +00:00
|
|
|
nsCOMPtr<nsIDocument> doc = do_QueryInterface(tempDoc);
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
|
2000-07-13 23:15:41 +00:00
|
|
|
|
2004-08-19 12:45:47 +00:00
|
|
|
// XXX Wallpaper over editor bug (editor tries to create elements with an
|
|
|
|
// empty nodename).
|
|
|
|
if (aTag.IsEmpty()) {
|
|
|
|
NS_ERROR("Don't pass an empty tag to nsEditor::CreateHTMLContent, "
|
|
|
|
"check caller.");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2010-07-23 09:49:57 +00:00
|
|
|
return doc->CreateElem(aTag, nsnull, kNameSpaceID_XHTML, PR_FALSE, aContent);
|
2000-07-13 23:15:41 +00:00
|
|
|
}
|
|
|
|
|
2002-01-09 13:51:37 +00:00
|
|
|
nsresult
|
2002-01-25 10:16:52 +00:00
|
|
|
nsEditor::SetAttributeOrEquivalent(nsIDOMElement * aElement,
|
2002-03-23 22:16:54 +00:00
|
|
|
const nsAString & aAttribute,
|
2002-09-17 12:04:59 +00:00
|
|
|
const nsAString & aValue,
|
|
|
|
PRBool aSuppressTransaction)
|
2002-01-09 13:51:37 +00:00
|
|
|
{
|
|
|
|
return SetAttribute(aElement, aAttribute, aValue);
|
|
|
|
}
|
2002-03-15 15:33:29 +00:00
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsEditor::RemoveAttributeOrEquivalent(nsIDOMElement * aElement,
|
2002-09-17 12:04:59 +00:00
|
|
|
const nsAString & aAttribute,
|
|
|
|
PRBool aSuppressTransaction)
|
2002-03-15 15:33:29 +00:00
|
|
|
{
|
|
|
|
return RemoveAttribute(aElement, aAttribute);
|
|
|
|
}
|
2005-01-26 01:40:30 +00:00
|
|
|
|
2010-06-10 01:16:58 +00:00
|
|
|
nsresult
|
|
|
|
nsEditor::HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent)
|
|
|
|
{
|
|
|
|
// NOTE: When you change this method, you should also change:
|
|
|
|
// * editor/libeditor/text/tests/test_texteditor_keyevent_handling.html
|
|
|
|
// * editor/libeditor/html/tests/test_htmleditor_keyevent_handling.html
|
|
|
|
//
|
|
|
|
// And also when you add new key handling, you need to change the subclass's
|
|
|
|
// HandleKeyPressEvent()'s switch statement.
|
|
|
|
|
|
|
|
nsKeyEvent* nativeKeyEvent = GetNativeKeyEvent(aKeyEvent);
|
|
|
|
NS_ENSURE_TRUE(nativeKeyEvent, NS_ERROR_UNEXPECTED);
|
|
|
|
NS_ASSERTION(nativeKeyEvent->message == NS_KEY_PRESS,
|
|
|
|
"HandleKeyPressEvent gets non-keypress event");
|
|
|
|
|
|
|
|
// if we are readonly or disabled, then do nothing.
|
|
|
|
if (IsReadonly() || IsDisabled()) {
|
|
|
|
// consume backspace for disabled and readonly textfields, to prevent
|
|
|
|
// back in history, which could be confusing to users
|
|
|
|
if (nativeKeyEvent->keyCode == nsIDOMKeyEvent::DOM_VK_BACK_SPACE) {
|
|
|
|
aKeyEvent->PreventDefault();
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (nativeKeyEvent->keyCode) {
|
|
|
|
case nsIDOMKeyEvent::DOM_VK_META:
|
|
|
|
case nsIDOMKeyEvent::DOM_VK_SHIFT:
|
|
|
|
case nsIDOMKeyEvent::DOM_VK_CONTROL:
|
|
|
|
case nsIDOMKeyEvent::DOM_VK_ALT:
|
|
|
|
aKeyEvent->PreventDefault(); // consumed
|
|
|
|
return NS_OK;
|
|
|
|
case nsIDOMKeyEvent::DOM_VK_BACK_SPACE:
|
|
|
|
if (nativeKeyEvent->isControl || nativeKeyEvent->isAlt ||
|
|
|
|
nativeKeyEvent->isMeta) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
DeleteSelection(nsIEditor::ePrevious);
|
|
|
|
aKeyEvent->PreventDefault(); // consumed
|
|
|
|
return NS_OK;
|
|
|
|
case nsIDOMKeyEvent::DOM_VK_DELETE:
|
|
|
|
// on certain platforms (such as windows) the shift key
|
|
|
|
// modifies what delete does (cmd_cut in this case).
|
|
|
|
// bailing here to allow the keybindings to do the cut.
|
|
|
|
if (nativeKeyEvent->isShift || nativeKeyEvent->isControl ||
|
|
|
|
nativeKeyEvent->isAlt || nativeKeyEvent->isMeta) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
DeleteSelection(nsIEditor::eNext);
|
|
|
|
aKeyEvent->PreventDefault(); // consumed
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2005-02-01 21:12:53 +00:00
|
|
|
nsresult
|
|
|
|
nsEditor::HandleInlineSpellCheck(PRInt32 action,
|
|
|
|
nsISelection *aSelection,
|
|
|
|
nsIDOMNode *previousSelectedNode,
|
|
|
|
PRInt32 previousSelectedOffset,
|
|
|
|
nsIDOMNode *aStartNode,
|
|
|
|
PRInt32 aStartOffset,
|
|
|
|
nsIDOMNode *aEndNode,
|
|
|
|
PRInt32 aEndOffset)
|
|
|
|
{
|
|
|
|
return mInlineSpellChecker ? mInlineSpellChecker->SpellCheckAfterEditorChange(action,
|
|
|
|
aSelection,
|
|
|
|
previousSelectedNode,
|
|
|
|
previousSelectedOffset,
|
|
|
|
aStartNode,
|
|
|
|
aStartOffset,
|
|
|
|
aEndNode,
|
|
|
|
aEndOffset) : NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-06-17 05:30:42 +00:00
|
|
|
already_AddRefed<nsIContent>
|
|
|
|
nsEditor::FindSelectionRoot(nsINode *aNode)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> rootContent = do_QueryInterface(GetRoot());
|
|
|
|
return rootContent.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsEditor::InitializeSelection(nsIDOMEventTarget* aFocusEventTarget)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsINode> targetNode = do_QueryInterface(aFocusEventTarget);
|
|
|
|
NS_ENSURE_TRUE(targetNode, NS_ERROR_INVALID_ARG);
|
|
|
|
nsCOMPtr<nsIContent> selectionRootContent = FindSelectionRoot(targetNode);
|
|
|
|
if (!selectionRootContent) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocument> targetDoc = do_QueryInterface(aFocusEventTarget);
|
|
|
|
PRBool isTargetDoc =
|
|
|
|
targetNode->IsNodeOfType(nsINode::eDOCUMENT) &&
|
|
|
|
targetNode->HasFlag(NODE_IS_EDITABLE);
|
|
|
|
|
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
|
|
nsresult rv = GetSelection(getter_AddRefs(selection));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
|
|
rv = GetPresShell(getter_AddRefs(presShell));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsISelectionController> selCon;
|
|
|
|
rv = GetSelectionController(getter_AddRefs(selCon));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsISelectionPrivate> selectionPrivate =
|
|
|
|
do_QueryInterface(selection);
|
|
|
|
NS_ENSURE_TRUE(selectionPrivate, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
|
|
// Init the caret
|
|
|
|
nsRefPtr<nsCaret> caret = presShell->GetCaret();
|
|
|
|
NS_ENSURE_TRUE(caret, NS_ERROR_UNEXPECTED);
|
|
|
|
caret->SetIgnoreUserModify(PR_FALSE);
|
|
|
|
caret->SetCaretDOMSelection(selection);
|
|
|
|
selCon->SetCaretReadOnly(IsReadonly());
|
|
|
|
selCon->SetCaretEnabled(PR_TRUE);
|
|
|
|
|
|
|
|
// Init selection
|
|
|
|
selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
|
|
|
|
selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
|
|
|
|
// If the computed selection root isn't root content, we should set it
|
|
|
|
// as selection ancestor limit. However, if that is root element, it means
|
|
|
|
// there is not limitation of the selection, then, we must set NULL.
|
|
|
|
// NOTE: If we set a root element to the ancestor limit, some selection
|
|
|
|
// methods don't work fine.
|
|
|
|
if (selectionRootContent->GetParent()) {
|
|
|
|
selectionPrivate->SetAncestorLimiter(selectionRootContent);
|
|
|
|
} else {
|
|
|
|
selectionPrivate->SetAncestorLimiter(nsnull);
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX What case needs this?
|
|
|
|
if (isTargetDoc) {
|
|
|
|
PRInt32 rangeCount;
|
|
|
|
selection->GetRangeCount(&rangeCount);
|
|
|
|
if (rangeCount == 0) {
|
|
|
|
BeginningOfDocument();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2005-03-24 19:00:01 +00:00
|
|
|
nsIDOMElement *
|
|
|
|
nsEditor::GetRoot()
|
|
|
|
{
|
|
|
|
if (!mRootElement)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMElement> root;
|
|
|
|
|
|
|
|
// Let GetRootElement() do the work
|
|
|
|
GetRootElement(getter_AddRefs(root));
|
|
|
|
}
|
|
|
|
|
|
|
|
return mRootElement;
|
|
|
|
}
|
|
|
|
|
2005-01-26 01:40:30 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditor::SwitchTextDirection()
|
|
|
|
{
|
2005-03-24 19:00:01 +00:00
|
|
|
// Get the current root direction from its frame
|
|
|
|
nsIDOMElement *rootElement = GetRoot();
|
2005-01-26 01:40:30 +00:00
|
|
|
|
2005-03-24 19:00:01 +00:00
|
|
|
nsresult rv;
|
2005-01-26 01:40:30 +00:00
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(rootElement, &rv);
|
2010-06-17 20:44:35 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2005-01-26 01:40:30 +00:00
|
|
|
|
2009-12-24 21:20:06 +00:00
|
|
|
nsIFrame *frame = content->GetPrimaryFrame();
|
2010-06-17 20:40:48 +00:00
|
|
|
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
|
2005-01-26 01:40:30 +00:00
|
|
|
|
|
|
|
// Apply the opposite direction
|
|
|
|
if (frame->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL)
|
|
|
|
rv = rootElement->SetAttribute(NS_LITERAL_STRING("dir"), NS_LITERAL_STRING("ltr"));
|
|
|
|
else
|
|
|
|
rv = rootElement->SetAttribute(NS_LITERAL_STRING("dir"), NS_LITERAL_STRING("rtl"));
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2002-11-22 03:30:59 +00:00
|
|
|
#if DEBUG_JOE
|
|
|
|
void
|
|
|
|
nsEditor::DumpNode(nsIDOMNode *aNode, PRInt32 indent)
|
|
|
|
{
|
|
|
|
PRInt32 i;
|
|
|
|
for (i=0; i<indent; i++)
|
|
|
|
printf(" ");
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aNode);
|
|
|
|
nsCOMPtr<nsIDOMDocumentFragment> docfrag = do_QueryInterface(aNode);
|
|
|
|
|
|
|
|
if (element || docfrag)
|
|
|
|
{
|
|
|
|
if (element)
|
|
|
|
{
|
|
|
|
nsAutoString tag;
|
|
|
|
element->GetTagName(tag);
|
2006-01-24 19:22:02 +00:00
|
|
|
printf("<%s>\n", NS_LossyConvertUTF16toASCII(tag).get());
|
2002-11-22 03:30:59 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printf("<document fragment>\n");
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIDOMNodeList> childList;
|
|
|
|
aNode->GetChildNodes(getter_AddRefs(childList));
|
2010-06-17 19:41:16 +00:00
|
|
|
NS_ENSURE_TRUE(childList, NS_ERROR_NULL_POINTER);
|
2002-11-22 03:30:59 +00:00
|
|
|
PRUint32 numChildren;
|
|
|
|
childList->GetLength(&numChildren);
|
|
|
|
nsCOMPtr<nsIDOMNode> child, tmp;
|
|
|
|
aNode->GetFirstChild(getter_AddRefs(child));
|
|
|
|
for (i=0; i<numChildren; i++)
|
|
|
|
{
|
|
|
|
DumpNode(child, indent+1);
|
|
|
|
child->GetNextSibling(getter_AddRefs(tmp));
|
|
|
|
child = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (IsTextNode(aNode))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(aNode);
|
|
|
|
nsAutoString str;
|
|
|
|
textNode->GetData(str);
|
2006-01-24 19:22:02 +00:00
|
|
|
nsCAutoString cstr;
|
|
|
|
LossyCopyUTF16toASCII(str, cstr);
|
|
|
|
cstr.ReplaceChar('\n', ' ');
|
|
|
|
printf("<textnode> %s\n", cstr.get());
|
2002-11-22 03:30:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2007-06-28 02:48:16 +00:00
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsEditor::IsModifiableNode(nsIDOMNode *aNode)
|
|
|
|
{
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2010-05-04 17:40:39 +00:00
|
|
|
|
2010-06-10 01:16:58 +00:00
|
|
|
nsKeyEvent*
|
|
|
|
nsEditor::GetNativeKeyEvent(nsIDOMKeyEvent* aDOMKeyEvent)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIPrivateDOMEvent> privDOMEvent = do_QueryInterface(aDOMKeyEvent);
|
|
|
|
NS_ENSURE_TRUE(privDOMEvent, nsnull);
|
|
|
|
nsEvent* nativeEvent = privDOMEvent->GetInternalNSEvent();
|
|
|
|
NS_ENSURE_TRUE(nativeEvent, nsnull);
|
|
|
|
NS_ENSURE_TRUE(nativeEvent->eventStructType == NS_KEY_EVENT, nsnull);
|
|
|
|
return static_cast<nsKeyEvent*>(nativeEvent);
|
|
|
|
}
|
|
|
|
|
2010-05-04 17:40:39 +00:00
|
|
|
PRBool
|
|
|
|
nsEditor::HasFocus()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsPIDOMEventTarget> piTarget = GetPIDOMEventTarget();
|
|
|
|
if (!piTarget) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
|
|
NS_ENSURE_TRUE(fm, PR_FALSE);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> content = fm->GetFocusedContent();
|
|
|
|
return SameCOMIdentity(content, piTarget);
|
|
|
|
}
|
2010-07-22 16:22:44 +00:00
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsEditor::IsActiveInDOMWindow()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsPIDOMEventTarget> piTarget = GetPIDOMEventTarget();
|
|
|
|
if (!piTarget) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
|
|
NS_ENSURE_TRUE(fm, PR_FALSE);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
|
|
|
|
nsPIDOMWindow* ourWindow = doc->GetWindow();
|
|
|
|
nsCOMPtr<nsPIDOMWindow> win;
|
|
|
|
nsIContent* content =
|
|
|
|
nsFocusManager::GetFocusedDescendant(ourWindow, PR_FALSE,
|
|
|
|
getter_AddRefs(win));
|
|
|
|
return SameCOMIdentity(content, piTarget);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsEditor::IsAcceptableInputEvent(nsIDOMEvent* aEvent)
|
|
|
|
{
|
|
|
|
// If the event is trusted, the event should always cause input.
|
|
|
|
nsCOMPtr<nsIDOMNSEvent> NSEvent = do_QueryInterface(aEvent);
|
|
|
|
NS_ENSURE_TRUE(NSEvent, PR_FALSE);
|
|
|
|
|
|
|
|
PRBool isTrusted;
|
|
|
|
nsresult rv = NSEvent->GetIsTrusted(&isTrusted);
|
|
|
|
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
|
|
|
if (isTrusted) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
// Otherwise, we shouldn't handle any input events when we're not an active
|
|
|
|
// element of the DOM window.
|
|
|
|
return IsActiveInDOMWindow();
|
|
|
|
}
|