1999-08-20 02:11:58 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
1999-03-01 22:54:47 +03:00
|
|
|
*
|
1999-11-06 06:43:54 +03:00
|
|
|
* The contents of this file are subject to the Netscape 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/NPL/
|
1999-03-01 22:54:47 +03:00
|
|
|
*
|
1999-11-06 06:43:54 +03: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-03-01 22:54:47 +03:00
|
|
|
*
|
1999-11-06 06:43:54 +03:00
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Netscape
|
1999-03-01 22:54:47 +03:00
|
|
|
* Communications Corporation. Portions created by Netscape are
|
1999-11-06 06:43:54 +03:00
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
|
|
* Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
2000-02-01 17:26:27 +03:00
|
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
1999-03-01 22:54:47 +03:00
|
|
|
*/
|
1999-09-18 03:15:12 +04:00
|
|
|
#include "nsICaret.h"
|
1999-03-01 22:54:47 +03:00
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
|
1999-03-01 22:54:47 +03:00
|
|
|
#include "nsHTMLEditor.h"
|
1999-03-29 12:02:05 +04:00
|
|
|
#include "nsHTMLEditRules.h"
|
2001-04-06 03:48:01 +04:00
|
|
|
#include "nsTextEditUtils.h"
|
2000-01-26 03:57:37 +03:00
|
|
|
#include "nsHTMLEditUtils.h"
|
1999-08-09 05:37:50 +04:00
|
|
|
|
1999-03-01 22:54:47 +03:00
|
|
|
#include "nsEditorEventListeners.h"
|
2001-04-06 03:48:01 +04:00
|
|
|
#include "TypeInState.h"
|
1999-08-09 05:37:50 +04:00
|
|
|
|
1999-07-05 03:01:10 +04:00
|
|
|
#include "nsIDOMText.h"
|
1999-04-08 04:46:10 +04:00
|
|
|
#include "nsIDOMNodeList.h"
|
1999-03-01 22:54:47 +03:00
|
|
|
#include "nsIDOMDocument.h"
|
2000-03-24 03:26:47 +03:00
|
|
|
#include "nsIDOMAttr.h"
|
1999-06-08 04:02:25 +04:00
|
|
|
#include "nsIDocument.h"
|
1999-03-01 22:54:47 +03:00
|
|
|
#include "nsIDOMEventReceiver.h"
|
1999-11-03 10:11:45 +03:00
|
|
|
#include "nsIDOMKeyEvent.h"
|
1999-03-01 22:54:47 +03:00
|
|
|
#include "nsIDOMKeyListener.h"
|
|
|
|
#include "nsIDOMMouseListener.h"
|
2000-08-05 00:51:33 +04:00
|
|
|
#include "nsIDOMMouseEvent.h"
|
2000-09-14 15:45:01 +04:00
|
|
|
#include "nsISelection.h"
|
|
|
|
#include "nsISelectionPrivate.h"
|
1999-03-30 02:01:26 +04:00
|
|
|
#include "nsIDOMHTMLAnchorElement.h"
|
|
|
|
#include "nsIDOMHTMLImageElement.h"
|
1999-12-15 02:07:12 +03:00
|
|
|
#include "nsISelectionController.h"
|
2000-05-13 12:04:29 +04:00
|
|
|
|
2001-04-06 03:48:01 +04:00
|
|
|
#include "TransactionFactory.h"
|
|
|
|
|
2000-05-13 12:04:29 +04:00
|
|
|
#include "nsIIndependentSelection.h" //domselections answer to frameselection
|
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
#include "nsICSSLoader.h"
|
|
|
|
#include "nsICSSStyleSheet.h"
|
|
|
|
#include "nsIHTMLContentContainer.h"
|
|
|
|
#include "nsIDocumentObserver.h"
|
|
|
|
#include "nsIDocumentStateListener.h"
|
|
|
|
|
|
|
|
#include "nsIStyleContext.h"
|
|
|
|
|
1999-04-20 21:47:12 +04:00
|
|
|
#include "nsIEnumerator.h"
|
1999-04-21 22:53:55 +04:00
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIContentIterator.h"
|
1999-03-01 22:54:47 +03:00
|
|
|
#include "nsEditorCID.h"
|
1999-04-21 22:53:55 +04:00
|
|
|
#include "nsLayoutCID.h"
|
|
|
|
#include "nsIDOMRange.h"
|
1999-06-11 01:31:42 +04:00
|
|
|
#include "nsIDOMNSRange.h"
|
1999-05-01 02:40:18 +04:00
|
|
|
#include "nsISupportsArray.h"
|
|
|
|
#include "nsVoidArray.h"
|
1999-05-14 00:59:08 +04:00
|
|
|
#include "nsFileSpec.h"
|
2000-05-12 18:57:03 +04:00
|
|
|
#include "nsIFile.h"
|
|
|
|
#include "nsIURL.h"
|
1999-03-09 12:44:27 +03:00
|
|
|
#include "nsIComponentManager.h"
|
1999-03-01 22:54:47 +03:00
|
|
|
#include "nsIServiceManager.h"
|
1999-05-27 01:40:51 +04:00
|
|
|
#include "nsWidgetsCID.h"
|
1999-06-07 23:32:36 +04:00
|
|
|
#include "nsIDocumentEncoder.h"
|
1999-06-11 01:31:42 +04:00
|
|
|
#include "nsIDOMDocumentFragment.h"
|
1999-06-10 04:35:02 +04:00
|
|
|
#include "nsIPresShell.h"
|
2000-05-15 09:18:45 +04:00
|
|
|
#include "nsIPresContext.h"
|
2001-04-06 03:48:01 +04:00
|
|
|
#include "nsIParserService.h"
|
2001-04-06 07:18:41 +04:00
|
|
|
#include "nsParserCIID.h"
|
1999-07-19 23:37:08 +04:00
|
|
|
#include "nsIImage.h"
|
1999-08-09 05:37:50 +04:00
|
|
|
#include "nsAOLCiter.h"
|
|
|
|
#include "nsInternetCiter.h"
|
1999-08-25 12:35:06 +04:00
|
|
|
#include "nsISupportsPrimitives.h"
|
2001-02-27 01:02:58 +03:00
|
|
|
#include "SetDocTitleTxn.h"
|
1999-08-09 05:37:50 +04:00
|
|
|
|
|
|
|
// netwerk
|
|
|
|
#include "nsIURI.h"
|
1999-11-30 07:50:42 +03:00
|
|
|
#include "nsNetUtil.h"
|
1999-07-19 23:37:08 +04:00
|
|
|
|
|
|
|
// Drag & Drop, Clipboard
|
|
|
|
#include "nsWidgetsCID.h"
|
|
|
|
#include "nsIClipboard.h"
|
|
|
|
#include "nsITransferable.h"
|
2000-04-25 18:15:04 +04:00
|
|
|
#include "nsIDragService.h"
|
2000-06-08 18:47:29 +04:00
|
|
|
#include "nsIDOMNSUIEvent.h"
|
1999-07-19 23:37:08 +04:00
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
// Transactionas
|
|
|
|
#include "nsStyleSheetTxns.h"
|
|
|
|
|
|
|
|
// Misc
|
|
|
|
#include "TextEditorTest.h"
|
|
|
|
#include "nsEditorUtils.h"
|
1999-08-28 06:40:18 +04:00
|
|
|
#include "nsIPref.h"
|
1999-08-09 05:37:50 +04:00
|
|
|
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
// HACK - CID for NS_CTRANSITIONAL_DTD_CID so that we can get at transitional dtd
|
|
|
|
#define NS_CTRANSITIONAL_DTD_CID \
|
|
|
|
{ 0x4611d482, 0x960a, 0x11d4, { 0x8e, 0xb0, 0xb6, 0x17, 0x66, 0x1b, 0x6f, 0x7c } }
|
1999-07-20 02:49:21 +04:00
|
|
|
|
2000-05-13 12:04:29 +04:00
|
|
|
|
1999-03-01 22:54:47 +03:00
|
|
|
static NS_DEFINE_CID(kHTMLEditorCID, NS_HTMLEDITOR_CID);
|
1999-04-21 22:53:55 +04:00
|
|
|
static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID);
|
2000-02-08 15:53:34 +03:00
|
|
|
static NS_DEFINE_IID(kSubtreeIteratorCID, NS_SUBTREEITERATOR_CID);
|
1999-06-08 10:04:51 +04:00
|
|
|
static NS_DEFINE_CID(kCRangeCID, NS_RANGE_CID);
|
2000-05-13 12:04:29 +04:00
|
|
|
static NS_DEFINE_CID(kCDOMSelectionCID, NS_DOMSELECTION_CID);
|
1999-08-09 05:37:50 +04:00
|
|
|
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
|
2001-04-06 03:48:01 +04:00
|
|
|
static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
static NS_DEFINE_CID(kCTransitionalDTDCID, NS_CTRANSITIONAL_DTD_CID);
|
1999-03-01 22:54:47 +03:00
|
|
|
|
2000-10-29 02:17:53 +04:00
|
|
|
#if defined(NS_DEBUG) && defined(DEBUG_buster)
|
|
|
|
static PRBool gNoisy = PR_FALSE;
|
|
|
|
#else
|
|
|
|
static const PRBool gNoisy = PR_FALSE;
|
|
|
|
#endif
|
|
|
|
|
1999-08-27 08:12:47 +04:00
|
|
|
// Some utilities to handle annoying overloading of "A" tag for link and named anchor
|
1999-07-28 03:59:22 +04:00
|
|
|
static char hrefText[] = "href";
|
1999-08-21 02:39:48 +04:00
|
|
|
static char anchorTxt[] = "anchor";
|
1999-07-28 03:59:22 +04:00
|
|
|
static char namedanchorText[] = "namedanchor";
|
1999-09-30 00:08:15 +04:00
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
// some prototypes for rules creation shortcuts
|
|
|
|
nsresult NS_NewTextEditRules(nsIEditRules** aInstancePtrResult);
|
|
|
|
nsresult NS_NewHTMLEditRules(nsIEditRules** aInstancePtrResult);
|
1999-06-10 04:35:02 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
#define IsLinkTag(s) (s.EqualsIgnoreCase(hrefText))
|
|
|
|
#define IsNamedAnchorTag(s) (s.EqualsIgnoreCase(anchorTxt) || s.EqualsIgnoreCase(namedanchorText))
|
1999-08-09 05:37:50 +04:00
|
|
|
|
1999-03-01 22:54:47 +03:00
|
|
|
nsHTMLEditor::nsHTMLEditor()
|
2001-01-28 23:13:07 +03:00
|
|
|
: nsPlaintextEditor()
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
, mIgnoreSpuriousDragEvent(PR_FALSE)
|
1999-08-09 05:37:50 +04:00
|
|
|
, mTypeInState(nsnull)
|
2000-03-21 09:05:24 +03:00
|
|
|
, mSelectedCellIndex(0)
|
1999-03-01 22:54:47 +03:00
|
|
|
{
|
1999-03-06 00:05:35 +03:00
|
|
|
// Done in nsEditor
|
|
|
|
// NS_INIT_REFCNT();
|
2000-01-31 13:30:12 +03:00
|
|
|
mBoldAtom = getter_AddRefs(NS_NewAtom("b"));
|
|
|
|
mItalicAtom = getter_AddRefs(NS_NewAtom("i"));
|
|
|
|
mUnderlineAtom = getter_AddRefs(NS_NewAtom("u"));
|
|
|
|
mFontAtom = getter_AddRefs(NS_NewAtom("font"));
|
2000-02-17 22:40:18 +03:00
|
|
|
mLinkAtom = getter_AddRefs(NS_NewAtom("a"));
|
1999-06-10 04:35:02 +04:00
|
|
|
}
|
1999-03-01 22:54:47 +03:00
|
|
|
|
|
|
|
nsHTMLEditor::~nsHTMLEditor()
|
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
// remove the rules as an action listener. Else we get a bad ownership loop later on.
|
|
|
|
// it's ok if the rules aren't a listener; we ignore the error.
|
|
|
|
nsCOMPtr<nsIEditActionListener> mListener = do_QueryInterface(mRules);
|
|
|
|
RemoveEditActionListener(mListener);
|
|
|
|
|
1999-03-01 22:54:47 +03:00
|
|
|
//the autopointers will clear themselves up.
|
1999-08-09 05:37:50 +04:00
|
|
|
//but we need to also remove the listeners or we have a leak
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection>selection;
|
1999-08-19 17:30:48 +04:00
|
|
|
nsresult result = GetSelection(getter_AddRefs(selection));
|
1999-09-30 00:08:15 +04:00
|
|
|
// if we don't get the selection, just skip this
|
1999-08-09 05:37:50 +04:00
|
|
|
if (NS_SUCCEEDED(result) && selection)
|
|
|
|
{
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
|
|
|
|
nsCOMPtr<nsISelectionListener>listener;
|
1999-08-09 05:37:50 +04:00
|
|
|
listener = do_QueryInterface(mTypeInState);
|
|
|
|
if (listener) {
|
2000-09-14 15:45:01 +04:00
|
|
|
selPriv->RemoveSelectionListener(listener);
|
1999-08-09 05:37:50 +04:00
|
|
|
}
|
|
|
|
}
|
1999-03-06 00:05:35 +03:00
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
NS_IF_RELEASE(mTypeInState);
|
1999-03-06 00:05:35 +03:00
|
|
|
}
|
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
NS_IMPL_ADDREF_INHERITED(nsHTMLEditor, nsEditor)
|
|
|
|
NS_IMPL_RELEASE_INHERITED(nsHTMLEditor, nsEditor)
|
|
|
|
|
1999-03-06 00:05:35 +03:00
|
|
|
|
|
|
|
NS_IMETHODIMP nsHTMLEditor::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|
|
|
{
|
1999-08-09 05:37:50 +04:00
|
|
|
if (!aInstancePtr)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
1999-03-06 00:05:35 +03:00
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
*aInstancePtr = nsnull;
|
|
|
|
|
2000-11-17 03:25:31 +03:00
|
|
|
if (aIID.Equals(NS_GET_IID(nsIPlaintextEditor))) {
|
|
|
|
*aInstancePtr = NS_STATIC_CAST(nsIPlaintextEditor*, this);
|
|
|
|
NS_ADDREF_THIS();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-02-01 17:26:27 +03:00
|
|
|
if (aIID.Equals(NS_GET_IID(nsIHTMLEditor))) {
|
1999-03-06 00:05:35 +03:00
|
|
|
*aInstancePtr = NS_STATIC_CAST(nsIHTMLEditor*, this);
|
|
|
|
NS_ADDREF_THIS();
|
|
|
|
return NS_OK;
|
1999-03-01 22:54:47 +03:00
|
|
|
}
|
2000-02-01 17:26:27 +03:00
|
|
|
if (aIID.Equals(NS_GET_IID(nsIEditorMailSupport))) {
|
1999-08-09 05:37:50 +04:00
|
|
|
*aInstancePtr = NS_STATIC_CAST(nsIEditorMailSupport*, this);
|
|
|
|
NS_ADDREF_THIS();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-02-01 17:26:27 +03:00
|
|
|
if (aIID.Equals(NS_GET_IID(nsITableEditor))) {
|
1999-08-09 05:37:50 +04:00
|
|
|
*aInstancePtr = NS_STATIC_CAST(nsITableEditor*, this);
|
|
|
|
NS_ADDREF_THIS();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-02-01 17:26:27 +03:00
|
|
|
if (aIID.Equals(NS_GET_IID(nsIEditorStyleSheets))) {
|
1999-08-09 05:37:50 +04:00
|
|
|
*aInstancePtr = NS_STATIC_CAST(nsIEditorStyleSheets*, this);
|
|
|
|
NS_ADDREF_THIS();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-02-01 17:26:27 +03:00
|
|
|
if (aIID.Equals(NS_GET_IID(nsICSSLoaderObserver))) {
|
1999-12-04 04:29:18 +03:00
|
|
|
*aInstancePtr = NS_STATIC_CAST(nsICSSLoaderObserver*, this);
|
|
|
|
NS_ADDREF_THIS();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
return nsEditor::QueryInterface(aIID, aInstancePtr);
|
1999-03-01 22:54:47 +03:00
|
|
|
}
|
|
|
|
|
1999-03-06 00:05:35 +03:00
|
|
|
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
NS_IMETHODIMP nsHTMLEditor::Init(nsIDOMDocument *aDoc,
|
2000-05-04 12:33:48 +04:00
|
|
|
nsIPresShell *aPresShell, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags)
|
1999-03-01 22:54:47 +03:00
|
|
|
{
|
1999-08-09 05:37:50 +04:00
|
|
|
NS_PRECONDITION(aDoc && aPresShell, "bad arg");
|
|
|
|
if (!aDoc || !aPresShell)
|
1999-09-30 00:08:15 +04:00
|
|
|
return NS_ERROR_NULL_POINTER;
|
1999-08-09 05:37:50 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult result = NS_OK, rulesRes = NS_OK;
|
2001-04-06 03:48:01 +04:00
|
|
|
|
|
|
|
// Init mEditProperty
|
|
|
|
result = NS_NewEditProperty(getter_AddRefs(mEditProperty));
|
|
|
|
if (NS_FAILED(result)) { return result; }
|
|
|
|
if (!mEditProperty) {return NS_ERROR_NULL_POINTER;}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (1)
|
|
|
|
{
|
|
|
|
// block to scope nsAutoEditInitRulesTrigger
|
|
|
|
nsAutoEditInitRulesTrigger rulesTrigger(NS_STATIC_CAST(nsPlaintextEditor*,this), rulesRes);
|
1999-08-09 05:37:50 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Init the plaintext editor
|
|
|
|
result = nsPlaintextEditor::Init(aDoc, aPresShell, aRoot, aSelCon, aFlags);
|
|
|
|
if (NS_FAILED(result)) { return result; }
|
2000-05-15 09:18:45 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// disable links
|
|
|
|
nsCOMPtr<nsIPresContext> context;
|
|
|
|
aPresShell->GetPresContext(getter_AddRefs(context));
|
|
|
|
if (!context) return NS_ERROR_NULL_POINTER;
|
|
|
|
if (!(mFlags & eEditorPlaintextMask))
|
|
|
|
context->SetLinkHandler(0);
|
1999-11-11 22:22:30 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMElement> bodyElement;
|
|
|
|
result = nsEditor::GetRootElement(getter_AddRefs(bodyElement));
|
|
|
|
if (NS_FAILED(result)) { return result; }
|
|
|
|
if (!bodyElement) { return NS_ERROR_NULL_POINTER; }
|
1999-08-09 05:37:50 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// init the type-in state
|
|
|
|
mTypeInState = new TypeInState();
|
|
|
|
if (!mTypeInState) {return NS_ERROR_NULL_POINTER;}
|
|
|
|
NS_ADDREF(mTypeInState);
|
|
|
|
|
|
|
|
nsCOMPtr<nsISelection>selection;
|
|
|
|
result = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(result)) { return result; }
|
|
|
|
if (selection)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
|
|
|
|
nsCOMPtr<nsISelectionListener>listener;
|
|
|
|
listener = do_QueryInterface(mTypeInState);
|
|
|
|
if (listener) {
|
|
|
|
selPriv->AddSelectionListener(listener);
|
|
|
|
}
|
1999-07-20 02:49:21 +04:00
|
|
|
}
|
1999-08-09 05:37:50 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Set up a DTD
|
|
|
|
mDTD = do_CreateInstance(kCTransitionalDTDCID);
|
|
|
|
if (!mDTD) result = NS_ERROR_FAILURE;
|
|
|
|
}
|
1999-11-29 11:28:46 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (NS_FAILED(rulesRes)) return rulesRes;
|
1999-08-23 10:42:04 +04:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::PostCreate()
|
|
|
|
{
|
|
|
|
nsresult result = InstallEventListeners();
|
|
|
|
if (NS_FAILED(result)) return result;
|
|
|
|
|
|
|
|
result = nsEditor::PostCreate();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::InstallEventListeners()
|
|
|
|
{
|
1999-08-25 14:51:55 +04:00
|
|
|
NS_ASSERTION(mDocWeak, "no document set on this editor");
|
|
|
|
if (!mDocWeak) return NS_ERROR_NOT_INITIALIZED;
|
1999-08-23 10:42:04 +04:00
|
|
|
|
|
|
|
nsresult result;
|
1999-08-09 05:37:50 +04:00
|
|
|
// get a key listener
|
|
|
|
result = NS_NewEditorKeyListener(getter_AddRefs(mKeyListenerP), this);
|
1999-08-19 17:30:48 +04:00
|
|
|
if (NS_FAILED(result)) {
|
1999-08-09 05:37:50 +04:00
|
|
|
HandleEventListenerError();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get a mouse listener
|
|
|
|
result = NS_NewEditorMouseListener(getter_AddRefs(mMouseListenerP), this);
|
1999-08-19 17:30:48 +04:00
|
|
|
if (NS_FAILED(result)) {
|
1999-08-09 05:37:50 +04:00
|
|
|
HandleEventListenerError();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get a text listener
|
|
|
|
result = NS_NewEditorTextListener(getter_AddRefs(mTextListenerP),this);
|
1999-08-19 17:30:48 +04:00
|
|
|
if (NS_FAILED(result)) {
|
1999-08-09 05:37:50 +04:00
|
|
|
#ifdef DEBUG_TAGUE
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("nsTextEditor.cpp: failed to get TextEvent Listener\n");
|
1999-08-09 05:37:50 +04:00
|
|
|
#endif
|
1999-09-30 00:08:15 +04:00
|
|
|
HandleEventListenerError();
|
|
|
|
return result;
|
1999-08-09 05:37:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// get a composition listener
|
|
|
|
result = NS_NewEditorCompositionListener(getter_AddRefs(mCompositionListenerP),this);
|
1999-08-19 17:30:48 +04:00
|
|
|
if (NS_FAILED(result)) {
|
1999-08-09 05:37:50 +04:00
|
|
|
#ifdef DEBUG_TAGUE
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("nsTextEditor.cpp: failed to get TextEvent Listener\n");
|
1999-08-09 05:37:50 +04:00
|
|
|
#endif
|
1999-09-30 00:08:15 +04:00
|
|
|
HandleEventListenerError();
|
|
|
|
return result;
|
1999-08-09 05:37:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// get a drag listener
|
|
|
|
result = NS_NewEditorDragListener(getter_AddRefs(mDragListenerP), this);
|
1999-08-19 17:30:48 +04:00
|
|
|
if (NS_FAILED(result)) {
|
1999-08-09 05:37:50 +04:00
|
|
|
HandleEventListenerError();
|
1999-08-19 17:30:48 +04:00
|
|
|
return result;
|
1999-08-09 05:37:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// get a focus listener
|
|
|
|
result = NS_NewEditorFocusListener(getter_AddRefs(mFocusListenerP), this);
|
1999-08-19 17:30:48 +04:00
|
|
|
if (NS_FAILED(result)) {
|
1999-08-09 05:37:50 +04:00
|
|
|
HandleEventListenerError();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMEventReceiver> erP;
|
2000-06-01 06:38:13 +04:00
|
|
|
result = GetDOMEventReceiver(getter_AddRefs(erP));
|
2000-05-04 12:33:48 +04:00
|
|
|
|
|
|
|
//end hack
|
1999-08-19 17:30:48 +04:00
|
|
|
if (NS_FAILED(result)) {
|
1999-08-09 05:37:50 +04:00
|
|
|
HandleEventListenerError();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// register the event listeners with the DOM event reveiver
|
2000-02-01 17:26:27 +03:00
|
|
|
result = erP->AddEventListenerByIID(mKeyListenerP, NS_GET_IID(nsIDOMKeyListener));
|
1999-08-09 05:37:50 +04:00
|
|
|
NS_ASSERTION(NS_SUCCEEDED(result), "failed to register key listener");
|
1999-09-30 00:08:15 +04:00
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{
|
2000-02-01 17:26:27 +03:00
|
|
|
result = erP->AddEventListenerByIID(mMouseListenerP, NS_GET_IID(nsIDOMMouseListener));
|
1999-09-30 00:08:15 +04:00
|
|
|
NS_ASSERTION(NS_SUCCEEDED(result), "failed to register mouse listener");
|
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{
|
2000-02-01 17:26:27 +03:00
|
|
|
result = erP->AddEventListenerByIID(mFocusListenerP, NS_GET_IID(nsIDOMFocusListener));
|
1999-09-30 00:08:15 +04:00
|
|
|
NS_ASSERTION(NS_SUCCEEDED(result), "failed to register focus listener");
|
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{
|
2000-02-01 17:26:27 +03:00
|
|
|
result = erP->AddEventListenerByIID(mTextListenerP, NS_GET_IID(nsIDOMTextListener));
|
1999-09-30 00:08:15 +04:00
|
|
|
NS_ASSERTION(NS_SUCCEEDED(result), "failed to register text listener");
|
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{
|
2000-02-01 17:26:27 +03:00
|
|
|
result = erP->AddEventListenerByIID(mCompositionListenerP, NS_GET_IID(nsIDOMCompositionListener));
|
1999-09-30 00:08:15 +04:00
|
|
|
NS_ASSERTION(NS_SUCCEEDED(result), "failed to register composition listener");
|
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{
|
2000-02-01 17:26:27 +03:00
|
|
|
result = erP->AddEventListenerByIID(mDragListenerP, NS_GET_IID(nsIDOMDragListener));
|
1999-09-30 00:08:15 +04:00
|
|
|
NS_ASSERTION(NS_SUCCEEDED(result), "failed to register drag listener");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-08-19 17:30:48 +04:00
|
|
|
if (NS_FAILED(result)) {
|
|
|
|
HandleEventListenerError();
|
|
|
|
}
|
1999-08-09 05:37:50 +04:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::GetFlags(PRUint32 *aFlags)
|
|
|
|
{
|
|
|
|
if (!mRules || !aFlags) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
return mRules->GetFlags(aFlags);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::SetFlags(PRUint32 aFlags)
|
|
|
|
{
|
|
|
|
if (!mRules) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
return mRules->SetFlags(aFlags);
|
1999-03-01 22:54:47 +03:00
|
|
|
}
|
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
NS_IMETHODIMP nsHTMLEditor::InitRules()
|
1999-03-29 12:02:05 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
// instantiate the rules for the html editor
|
|
|
|
nsresult res = NS_NewHTMLEditRules(getter_AddRefs(mRules));
|
2000-03-24 03:26:47 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!mRules) return NS_ERROR_UNEXPECTED;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mRules->Init(NS_STATIC_CAST(nsPlaintextEditor*,this), mFlags);
|
2000-03-24 03:26:47 +03:00
|
|
|
|
|
|
|
return res;
|
1999-03-29 12:02:05 +04:00
|
|
|
}
|
|
|
|
|
2001-04-06 03:48:01 +04:00
|
|
|
/**
|
|
|
|
* Returns true if the id represents an element of block type.
|
|
|
|
* Can be used to determine if a new paragraph should be started.
|
|
|
|
*/
|
|
|
|
nsresult
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::NodeIsBlockStatic(nsIDOMNode *aNode, PRBool *aIsBlock)
|
2001-04-06 03:48:01 +04:00
|
|
|
{
|
2001-04-07 04:45:26 +04:00
|
|
|
if (!aNode || !aIsBlock) { return NS_ERROR_NULL_POINTER; }
|
2001-04-06 03:48:01 +04:00
|
|
|
|
2001-04-06 07:18:41 +04:00
|
|
|
//#define USE_PARSER_FOR_BLOCKNESS 1
|
|
|
|
#ifdef USE_PARSER_FOR_BLOCKNESS
|
|
|
|
// We want to use the parser rather than keeping this info
|
|
|
|
// here in the editor, but the problem is that the ownership
|
|
|
|
// model for the parser service is unclear; we don't want to
|
|
|
|
// have to get it every time, but if we keep it statically
|
|
|
|
// here, it may show up as a leak.
|
2001-04-06 03:48:01 +04:00
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMElement>element;
|
|
|
|
element = do_QueryInterface(aNode);
|
|
|
|
if (!element)
|
|
|
|
{
|
|
|
|
// We don't have an element -- probably a text node
|
2001-04-07 04:45:26 +04:00
|
|
|
*aIsBlock = PR_FALSE;
|
2001-04-06 03:48:01 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-04-07 04:45:26 +04:00
|
|
|
*aIsBlock = PR_FALSE;
|
2001-04-06 03:48:01 +04:00
|
|
|
|
|
|
|
// Get the node name and atom:
|
|
|
|
nsAutoString tagName;
|
|
|
|
rv = element->GetTagName(tagName);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
tagName.ToLowerCase();
|
2001-04-06 07:18:41 +04:00
|
|
|
nsCOMPtr<nsIAtom> tagAtom = getter_AddRefs(NS_NewAtom(tagName));
|
2001-04-06 03:48:01 +04:00
|
|
|
if (!tagAtom) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
static nsCOMPtr<nsIParserService> sParserService;
|
|
|
|
if (!sParserService) {
|
|
|
|
sParserService = do_GetService(kParserServiceCID, &rv);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Nodes we know we want to treat as block
|
|
|
|
// even though the parser says they're not:
|
|
|
|
if (tagAtom==nsIEditProperty::body ||
|
|
|
|
tagAtom==nsIEditProperty::tbody ||
|
|
|
|
tagAtom==nsIEditProperty::thead ||
|
|
|
|
tagAtom==nsIEditProperty::tfoot ||
|
|
|
|
tagAtom==nsIEditProperty::tr ||
|
|
|
|
tagAtom==nsIEditProperty::th ||
|
|
|
|
tagAtom==nsIEditProperty::td ||
|
|
|
|
tagAtom==nsIEditProperty::pre)
|
|
|
|
{
|
2001-04-07 04:45:26 +04:00
|
|
|
*aIsBlock = PR_TRUE;
|
2001-04-06 03:48:01 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This sucks. The parser service's isBlock requires a string,
|
|
|
|
// so we have to get the name atom, convert it into a string, call
|
|
|
|
// the parser service to get the id, in order to call the parser
|
|
|
|
// service to ask about blockness.
|
|
|
|
// Harish is working on a more efficient API we can use.
|
|
|
|
PRInt32 id;
|
|
|
|
rv = sParserService->HTMLStringTagToId(tagName, &id);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
2001-04-07 04:45:26 +04:00
|
|
|
rv = sParserService->IsBlock(id, *aIsBlock);
|
2001-04-06 03:48:01 +04:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
// Check this against what we would have said with the old code:
|
|
|
|
if (tagAtom==nsIEditProperty::p ||
|
|
|
|
tagAtom==nsIEditProperty::div ||
|
|
|
|
tagAtom==nsIEditProperty::blockquote ||
|
|
|
|
tagAtom==nsIEditProperty::h1 ||
|
|
|
|
tagAtom==nsIEditProperty::h2 ||
|
|
|
|
tagAtom==nsIEditProperty::h3 ||
|
|
|
|
tagAtom==nsIEditProperty::h4 ||
|
|
|
|
tagAtom==nsIEditProperty::h5 ||
|
|
|
|
tagAtom==nsIEditProperty::h6 ||
|
|
|
|
tagAtom==nsIEditProperty::ul ||
|
|
|
|
tagAtom==nsIEditProperty::ol ||
|
|
|
|
tagAtom==nsIEditProperty::dl ||
|
|
|
|
tagAtom==nsIEditProperty::noscript ||
|
|
|
|
tagAtom==nsIEditProperty::form ||
|
|
|
|
tagAtom==nsIEditProperty::hr ||
|
|
|
|
tagAtom==nsIEditProperty::table ||
|
|
|
|
tagAtom==nsIEditProperty::fieldset ||
|
|
|
|
tagAtom==nsIEditProperty::address ||
|
|
|
|
tagAtom==nsIEditProperty::caption ||
|
|
|
|
tagAtom==nsIEditProperty::col ||
|
|
|
|
tagAtom==nsIEditProperty::colgroup ||
|
|
|
|
tagAtom==nsIEditProperty::li ||
|
|
|
|
tagAtom==nsIEditProperty::dt ||
|
|
|
|
tagAtom==nsIEditProperty::dd ||
|
|
|
|
tagAtom==nsIEditProperty::legend )
|
|
|
|
{
|
2001-04-07 04:45:26 +04:00
|
|
|
if (!(*aIsBlock))
|
2001-04-06 03:48:01 +04:00
|
|
|
{
|
|
|
|
nsAutoString assertmsg (NS_LITERAL_STRING("Parser and editor disagree on blockness: "));
|
|
|
|
assertmsg.Append(tagName);
|
|
|
|
char* assertstr = assertmsg.ToNewCString();
|
2001-04-07 04:45:26 +04:00
|
|
|
NS_ASSERTION(*aIsBlock, assertstr);
|
2001-04-06 03:48:01 +04:00
|
|
|
Recycle(assertstr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* DEBUG */
|
|
|
|
|
|
|
|
return rv;
|
2001-04-06 07:18:41 +04:00
|
|
|
#else /* USE_PARSER_FOR_BLOCKNESS */
|
|
|
|
nsresult result = NS_ERROR_FAILURE;
|
2001-04-07 04:45:26 +04:00
|
|
|
*aIsBlock = PR_FALSE;
|
2001-04-06 07:18:41 +04:00
|
|
|
nsCOMPtr<nsIDOMElement>element;
|
|
|
|
element = do_QueryInterface(aNode);
|
|
|
|
if (element)
|
|
|
|
{
|
|
|
|
nsAutoString tagName;
|
|
|
|
result = element->GetTagName(tagName);
|
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{
|
|
|
|
tagName.ToLowerCase();
|
|
|
|
nsIAtom *tagAtom = NS_NewAtom(tagName);
|
|
|
|
if (!tagAtom) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
|
|
|
|
if (tagAtom==nsIEditProperty::p ||
|
|
|
|
tagAtom==nsIEditProperty::div ||
|
|
|
|
tagAtom==nsIEditProperty::blockquote ||
|
|
|
|
tagAtom==nsIEditProperty::h1 ||
|
|
|
|
tagAtom==nsIEditProperty::h2 ||
|
|
|
|
tagAtom==nsIEditProperty::h3 ||
|
|
|
|
tagAtom==nsIEditProperty::h4 ||
|
|
|
|
tagAtom==nsIEditProperty::h5 ||
|
|
|
|
tagAtom==nsIEditProperty::h6 ||
|
|
|
|
tagAtom==nsIEditProperty::ul ||
|
|
|
|
tagAtom==nsIEditProperty::ol ||
|
|
|
|
tagAtom==nsIEditProperty::dl ||
|
|
|
|
tagAtom==nsIEditProperty::pre ||
|
|
|
|
tagAtom==nsIEditProperty::noscript ||
|
|
|
|
tagAtom==nsIEditProperty::form ||
|
|
|
|
tagAtom==nsIEditProperty::hr ||
|
|
|
|
tagAtom==nsIEditProperty::table ||
|
|
|
|
tagAtom==nsIEditProperty::fieldset ||
|
|
|
|
tagAtom==nsIEditProperty::address ||
|
|
|
|
tagAtom==nsIEditProperty::body ||
|
|
|
|
tagAtom==nsIEditProperty::tr ||
|
|
|
|
tagAtom==nsIEditProperty::td ||
|
|
|
|
tagAtom==nsIEditProperty::th ||
|
|
|
|
tagAtom==nsIEditProperty::caption ||
|
|
|
|
tagAtom==nsIEditProperty::col ||
|
|
|
|
tagAtom==nsIEditProperty::colgroup ||
|
|
|
|
tagAtom==nsIEditProperty::tbody ||
|
|
|
|
tagAtom==nsIEditProperty::thead ||
|
|
|
|
tagAtom==nsIEditProperty::tfoot ||
|
|
|
|
tagAtom==nsIEditProperty::li ||
|
|
|
|
tagAtom==nsIEditProperty::dt ||
|
|
|
|
tagAtom==nsIEditProperty::dd ||
|
|
|
|
tagAtom==nsIEditProperty::legend )
|
|
|
|
{
|
2001-04-07 04:45:26 +04:00
|
|
|
*aIsBlock = PR_TRUE;
|
2001-04-06 07:18:41 +04:00
|
|
|
}
|
|
|
|
NS_RELEASE(tagAtom);
|
|
|
|
result = NS_OK;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// We don't have an element -- probably a text node
|
|
|
|
nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(aNode);
|
|
|
|
if (nodeAsText)
|
|
|
|
{
|
2001-04-07 04:45:26 +04:00
|
|
|
*aIsBlock = PR_FALSE;
|
2001-04-06 07:18:41 +04:00
|
|
|
result = NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
|
|
|
|
#endif /* USE_PARSER_FOR_BLOCKNESS */
|
2001-04-06 03:48:01 +04:00
|
|
|
}
|
|
|
|
|
2001-04-07 04:45:26 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::NodeIsBlock(nsIDOMNode *aNode, PRBool *aIsBlock)
|
2001-04-06 03:48:01 +04:00
|
|
|
{
|
|
|
|
return NodeIsBlockStatic(aNode, aIsBlock);
|
|
|
|
}
|
|
|
|
|
2001-04-17 14:15:05 +04:00
|
|
|
PRBool
|
|
|
|
nsHTMLEditor::IsBlockNode(nsIDOMNode *aNode)
|
|
|
|
{
|
|
|
|
PRBool isBlock;
|
|
|
|
NodeIsBlockStatic(aNode, &isBlock);
|
|
|
|
return isBlock;
|
|
|
|
}
|
|
|
|
|
2001-04-07 04:45:26 +04:00
|
|
|
// Non-static version for the nsIEditor interface and JavaScript
|
2001-02-27 01:02:58 +03:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::SetDocumentTitle(const nsAReadableString &aTitle)
|
2001-02-27 01:02:58 +03:00
|
|
|
{
|
|
|
|
SetDocTitleTxn *txn;
|
|
|
|
nsresult result = TransactionFactory::GetNewTransaction(SetDocTitleTxn::GetCID(), (EditTxn **)&txn);
|
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{
|
2001-04-07 04:45:26 +04:00
|
|
|
result = txn->Init(this, &aTitle);
|
2001-02-27 01:02:58 +03:00
|
|
|
|
|
|
|
if (NS_SUCCEEDED(result))
|
|
|
|
{
|
2001-04-12 07:41:06 +04:00
|
|
|
//Don't let Rules System change the selection
|
|
|
|
nsAutoTxnsConserveSelection dontChangeSelection(this);
|
|
|
|
|
2001-02-27 01:02:58 +03:00
|
|
|
result = nsEditor::Do(txn);
|
|
|
|
}
|
|
|
|
// The transaction system (if any) has taken ownwership of txn
|
|
|
|
NS_IF_RELEASE(txn);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2000-01-19 00:50:15 +03:00
|
|
|
|
2001-04-06 03:48:01 +04:00
|
|
|
/* ------------ Block methods moved from nsEditor -------------- */
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetBlockNodeParent: returns enclosing block level ancestor, if any
|
|
|
|
//
|
|
|
|
nsCOMPtr<nsIDOMNode>
|
|
|
|
nsHTMLEditor::GetBlockNodeParent(nsIDOMNode *aNode)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> tmp;
|
|
|
|
nsCOMPtr<nsIDOMNode> p;
|
|
|
|
|
|
|
|
if (!aNode)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("null node passed to GetBlockNodeParent()");
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_FAILED(aNode->GetParentNode(getter_AddRefs(p)))) // no parent, ran off top of tree
|
|
|
|
return tmp;
|
|
|
|
|
|
|
|
while (p)
|
|
|
|
{
|
|
|
|
PRBool isBlock;
|
2001-04-07 04:45:26 +04:00
|
|
|
if (NS_FAILED(NodeIsBlockStatic(p, &isBlock)) || isBlock)
|
2001-04-06 03:48:01 +04:00
|
|
|
break;
|
|
|
|
if ( NS_FAILED(p->GetParentNode(getter_AddRefs(tmp))) || !tmp) // no parent, ran off top of tree
|
|
|
|
return p;
|
|
|
|
|
|
|
|
p = tmp;
|
|
|
|
}
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// HasSameBlockNodeParent: true if nodes have same block level ancestor
|
|
|
|
//
|
|
|
|
PRBool
|
|
|
|
nsHTMLEditor::HasSameBlockNodeParent(nsIDOMNode *aNode1, nsIDOMNode *aNode2)
|
|
|
|
{
|
|
|
|
if (!aNode1 || !aNode2)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("null node passed to HasSameBlockNodeParent()");
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aNode1 == aNode2)
|
|
|
|
return PR_TRUE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> p1 = GetBlockNodeParent(aNode1);
|
|
|
|
nsCOMPtr<nsIDOMNode> p2 = GetBlockNodeParent(aNode2);
|
|
|
|
|
|
|
|
return (p1 == p2);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetBlockSection: return leftmost/rightmost nodes in aChild's block
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::GetBlockSection(nsIDOMNode *aChild,
|
|
|
|
nsIDOMNode **aLeftNode,
|
|
|
|
nsIDOMNode **aRightNode)
|
|
|
|
{
|
|
|
|
nsresult result = NS_OK;
|
|
|
|
if (!aChild || !aLeftNode || !aRightNode) {return NS_ERROR_NULL_POINTER;}
|
|
|
|
*aLeftNode = aChild;
|
|
|
|
*aRightNode = aChild;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode>sibling;
|
|
|
|
result = aChild->GetPreviousSibling(getter_AddRefs(sibling));
|
|
|
|
while ((NS_SUCCEEDED(result)) && sibling)
|
|
|
|
{
|
|
|
|
PRBool isBlock;
|
2001-04-07 04:45:26 +04:00
|
|
|
NodeIsBlockStatic(sibling, &isBlock);
|
2001-04-06 03:48:01 +04:00
|
|
|
if (isBlock)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
|
|
|
|
if (!nodeAsText) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// XXX: needs some logic to work for other leaf nodes besides text!
|
|
|
|
}
|
|
|
|
*aLeftNode = sibling;
|
|
|
|
result = (*aLeftNode)->GetPreviousSibling(getter_AddRefs(sibling));
|
|
|
|
}
|
|
|
|
NS_ADDREF((*aLeftNode));
|
|
|
|
// now do the right side
|
|
|
|
result = aChild->GetNextSibling(getter_AddRefs(sibling));
|
|
|
|
while ((NS_SUCCEEDED(result)) && sibling)
|
|
|
|
{
|
|
|
|
PRBool isBlock;
|
2001-04-07 04:45:26 +04:00
|
|
|
NodeIsBlockStatic(sibling, &isBlock);
|
2001-04-06 03:48:01 +04:00
|
|
|
if (isBlock)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
|
|
|
|
if (!nodeAsText) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*aRightNode = sibling;
|
|
|
|
result = (*aRightNode)->GetNextSibling(getter_AddRefs(sibling));
|
|
|
|
}
|
|
|
|
NS_ADDREF((*aRightNode));
|
|
|
|
if (gNoisy) { printf("GetBlockSection returning %p %p\n",
|
|
|
|
(void*)(*aLeftNode), (void*)(*aRightNode)); }
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetBlockSectionsForRange: return list of block sections that intersect
|
|
|
|
// this range
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::GetBlockSectionsForRange(nsIDOMRange *aRange,
|
|
|
|
nsISupportsArray *aSections)
|
|
|
|
{
|
|
|
|
if (!aRange || !aSections) {return NS_ERROR_NULL_POINTER;}
|
|
|
|
|
|
|
|
nsresult result;
|
|
|
|
nsCOMPtr<nsIContentIterator>iter;
|
|
|
|
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
|
|
|
|
NS_GET_IID(nsIContentIterator), getter_AddRefs(iter));
|
|
|
|
if ((NS_SUCCEEDED(result)) && iter)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMRange> lastRange;
|
|
|
|
iter->Init(aRange);
|
|
|
|
nsCOMPtr<nsIContent> currentContent;
|
|
|
|
iter->CurrentNode(getter_AddRefs(currentContent));
|
|
|
|
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode>currentNode = do_QueryInterface(currentContent);
|
|
|
|
if (currentNode)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIAtom> currentContentTag;
|
|
|
|
currentContent->GetTag(*getter_AddRefs(currentContentTag));
|
|
|
|
// <BR> divides block content ranges. We can achieve this by nulling out lastRange
|
|
|
|
if (nsIEditProperty::br==currentContentTag.get())
|
|
|
|
{
|
|
|
|
lastRange = do_QueryInterface(nsnull);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PRBool isNotInlineOrText;
|
2001-04-07 04:45:26 +04:00
|
|
|
result = NodeIsBlockStatic(currentNode, &isNotInlineOrText);
|
2001-04-06 03:48:01 +04:00
|
|
|
if (isNotInlineOrText)
|
|
|
|
{
|
|
|
|
PRUint16 nodeType;
|
|
|
|
currentNode->GetNodeType(&nodeType);
|
|
|
|
if (nsIDOMNode::TEXT_NODE == nodeType) {
|
|
|
|
isNotInlineOrText = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (PR_FALSE==isNotInlineOrText)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode>leftNode;
|
|
|
|
nsCOMPtr<nsIDOMNode>rightNode;
|
|
|
|
result = GetBlockSection(currentNode,
|
|
|
|
getter_AddRefs(leftNode),
|
|
|
|
getter_AddRefs(rightNode));
|
|
|
|
if (gNoisy) {printf("currentNode %p has block content (%p,%p)\n", (void*)currentNode.get(), (void*)leftNode.get(), (void*)rightNode.get());}
|
|
|
|
if ((NS_SUCCEEDED(result)) && leftNode && rightNode)
|
|
|
|
{
|
|
|
|
// add range to the list if it doesn't overlap with the previous range
|
|
|
|
PRBool addRange=PR_TRUE;
|
|
|
|
if (lastRange)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> lastStartNode;
|
|
|
|
nsCOMPtr<nsIDOMElement> blockParentOfLastStartNode;
|
|
|
|
lastRange->GetStartContainer(getter_AddRefs(lastStartNode));
|
|
|
|
blockParentOfLastStartNode = do_QueryInterface(GetBlockNodeParent(lastStartNode));
|
|
|
|
if (blockParentOfLastStartNode)
|
|
|
|
{
|
|
|
|
if (gNoisy) {printf("lastStartNode %p has block parent %p\n", (void*)lastStartNode.get(), (void*)blockParentOfLastStartNode.get());}
|
|
|
|
nsCOMPtr<nsIDOMElement> blockParentOfLeftNode;
|
|
|
|
blockParentOfLeftNode = do_QueryInterface(GetBlockNodeParent(leftNode));
|
|
|
|
if (blockParentOfLeftNode)
|
|
|
|
{
|
|
|
|
if (gNoisy) {printf("leftNode %p has block parent %p\n", (void*)leftNode.get(), (void*)blockParentOfLeftNode.get());}
|
|
|
|
if (blockParentOfLastStartNode==blockParentOfLeftNode) {
|
|
|
|
addRange = PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (PR_TRUE==addRange)
|
|
|
|
{
|
|
|
|
if (gNoisy) {printf("adding range, setting lastRange with start node %p\n", (void*)leftNode.get());}
|
|
|
|
nsCOMPtr<nsIDOMRange> range;
|
|
|
|
result = nsComponentManager::CreateInstance(kCRangeCID, nsnull,
|
|
|
|
NS_GET_IID(nsIDOMRange), getter_AddRefs(range));
|
|
|
|
if ((NS_SUCCEEDED(result)) && range)
|
|
|
|
{ // initialize the range
|
|
|
|
range->SetStart(leftNode, 0);
|
|
|
|
range->SetEnd(rightNode, 0);
|
|
|
|
aSections->AppendElement(range);
|
|
|
|
lastRange = do_QueryInterface(range);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* do not check result here, and especially do not return the result code.
|
|
|
|
* we rely on iter->IsDone to tell us when the iteration is complete
|
|
|
|
*/
|
|
|
|
iter->Next();
|
|
|
|
iter->CurrentNode(getter_AddRefs(currentContent));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// NextNodeInBlock: gets the next/prev node in the block, if any. Next node
|
|
|
|
// must be an element or text node, others are ignored
|
|
|
|
nsCOMPtr<nsIDOMNode>
|
|
|
|
nsHTMLEditor::NextNodeInBlock(nsIDOMNode *aNode, IterDirection aDir)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> nullNode;
|
|
|
|
nsCOMPtr<nsIContent> content;
|
|
|
|
nsCOMPtr<nsIContent> blockContent;
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
nsCOMPtr<nsIDOMNode> blockParent;
|
|
|
|
|
|
|
|
if (!aNode) return nullNode;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContentIterator> iter;
|
|
|
|
if (NS_FAILED(nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
|
|
|
|
NS_GET_IID(nsIContentIterator),
|
|
|
|
getter_AddRefs(iter))))
|
|
|
|
return nullNode;
|
|
|
|
|
|
|
|
// much gnashing of teeth as we twit back and forth between content and domnode types
|
|
|
|
content = do_QueryInterface(aNode);
|
|
|
|
PRBool isBlock;
|
2001-04-07 04:45:26 +04:00
|
|
|
if (NS_SUCCEEDED(NodeIsBlockStatic(aNode, &isBlock)) && isBlock)
|
2001-04-06 03:48:01 +04:00
|
|
|
{
|
|
|
|
blockParent = do_QueryInterface(aNode);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
blockParent = GetBlockNodeParent(aNode);
|
|
|
|
}
|
|
|
|
if (!blockParent) return nullNode;
|
|
|
|
blockContent = do_QueryInterface(blockParent);
|
|
|
|
if (!blockContent) return nullNode;
|
|
|
|
|
|
|
|
if (NS_FAILED(iter->Init(blockContent))) return nullNode;
|
|
|
|
if (NS_FAILED(iter->PositionAt(content))) return nullNode;
|
|
|
|
|
|
|
|
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
|
|
|
{
|
|
|
|
if (NS_FAILED(iter->CurrentNode(getter_AddRefs(content)))) return nullNode;
|
|
|
|
// ignore nodes that aren't elements or text, or that are the block parent
|
|
|
|
node = do_QueryInterface(content);
|
|
|
|
if (node && IsTextOrElementNode(node) && (node != blockParent) && (node.get() != aNode))
|
|
|
|
return node;
|
|
|
|
|
|
|
|
if (aDir == kIterForward)
|
|
|
|
iter->Next();
|
|
|
|
else
|
|
|
|
iter->Prev();
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const PRUnichar nbsp = 160;
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// IsNextCharWhitespace: checks the adjacent content in the same block
|
|
|
|
// to see if following selection is whitespace or nbsp
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::IsNextCharWhitespace(nsIDOMNode *aParentNode,
|
|
|
|
PRInt32 aOffset,
|
|
|
|
PRBool *outIsSpace,
|
|
|
|
PRBool *outIsNBSP,
|
|
|
|
nsCOMPtr<nsIDOMNode> *outNode,
|
|
|
|
PRInt32 *outOffset)
|
|
|
|
{
|
|
|
|
if (!outIsSpace || !outIsNBSP) return NS_ERROR_NULL_POINTER;
|
|
|
|
*outIsSpace = PR_FALSE;
|
|
|
|
*outIsNBSP = PR_FALSE;
|
|
|
|
if (outNode) *outNode = nsnull;
|
|
|
|
if (outOffset) *outOffset = -1;
|
|
|
|
|
|
|
|
nsAutoString tempString;
|
|
|
|
PRUint32 strLength;
|
|
|
|
nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(aParentNode);
|
|
|
|
if (textNode)
|
|
|
|
{
|
|
|
|
textNode->GetLength(&strLength);
|
|
|
|
if ((PRUint32)aOffset < strLength)
|
|
|
|
{
|
|
|
|
// easy case: next char is in same node
|
|
|
|
textNode->SubstringData(aOffset,aOffset+1,tempString);
|
|
|
|
*outIsSpace = nsCRT::IsAsciiSpace(tempString.First());
|
|
|
|
*outIsNBSP = (tempString.First() == nbsp);
|
|
|
|
if (outNode) *outNode = do_QueryInterface(aParentNode);
|
|
|
|
if (outOffset) *outOffset = aOffset+1; // yes, this is _past_ the character;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// harder case: next char in next node.
|
|
|
|
nsCOMPtr<nsIDOMNode> node = NextNodeInBlock(aParentNode, kIterForward);
|
|
|
|
nsCOMPtr<nsIDOMNode> tmp;
|
|
|
|
while (node)
|
|
|
|
{
|
|
|
|
PRBool isBlock (PR_FALSE);
|
2001-04-07 04:45:26 +04:00
|
|
|
NodeIsBlock(node, &isBlock);
|
2001-04-06 03:48:01 +04:00
|
|
|
if (isBlock) // skip over bold, italic, link, ect nodes
|
|
|
|
{
|
|
|
|
if (IsTextNode(node) && IsEditable(node))
|
|
|
|
{
|
|
|
|
textNode = do_QueryInterface(node);
|
|
|
|
textNode->GetLength(&strLength);
|
|
|
|
if (strLength)
|
|
|
|
{
|
|
|
|
textNode->SubstringData(0,1,tempString);
|
|
|
|
*outIsSpace = nsCRT::IsAsciiSpace(tempString.First());
|
|
|
|
*outIsNBSP = (tempString.First() == nbsp);
|
|
|
|
if (outNode) *outNode = do_QueryInterface(node);
|
|
|
|
if (outOffset) *outOffset = 1; // yes, this is _past_ the character;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
// else it's an empty text node, or not editable; skip it.
|
|
|
|
}
|
|
|
|
else // node is an image or some other thingy that doesn't count as whitespace
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tmp = node;
|
|
|
|
node = NextNodeInBlock(tmp, kIterForward);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// IsPrevCharWhitespace: checks the adjacent content in the same block
|
|
|
|
// to see if following selection is whitespace
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::IsPrevCharWhitespace(nsIDOMNode *aParentNode,
|
|
|
|
PRInt32 aOffset,
|
|
|
|
PRBool *outIsSpace,
|
|
|
|
PRBool *outIsNBSP,
|
|
|
|
nsCOMPtr<nsIDOMNode> *outNode,
|
|
|
|
PRInt32 *outOffset)
|
|
|
|
{
|
|
|
|
if (!outIsSpace || !outIsNBSP) return NS_ERROR_NULL_POINTER;
|
|
|
|
*outIsSpace = PR_FALSE;
|
|
|
|
*outIsNBSP = PR_FALSE;
|
|
|
|
if (outNode) *outNode = nsnull;
|
|
|
|
if (outOffset) *outOffset = -1;
|
|
|
|
|
|
|
|
nsAutoString tempString;
|
|
|
|
PRUint32 strLength;
|
|
|
|
nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(aParentNode);
|
|
|
|
if (textNode)
|
|
|
|
{
|
|
|
|
if (aOffset > 0)
|
|
|
|
{
|
|
|
|
// easy case: prev char is in same node
|
|
|
|
textNode->SubstringData(aOffset-1,aOffset,tempString);
|
|
|
|
*outIsSpace = nsCRT::IsAsciiSpace(tempString.First());
|
|
|
|
*outIsNBSP = (tempString.First() == nbsp);
|
|
|
|
if (outNode) *outNode = do_QueryInterface(aParentNode);
|
|
|
|
if (outOffset) *outOffset = aOffset-1;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// harder case: prev char in next node
|
|
|
|
nsCOMPtr<nsIDOMNode> node = NextNodeInBlock(aParentNode, kIterBackward);
|
|
|
|
nsCOMPtr<nsIDOMNode> tmp;
|
|
|
|
while (node)
|
|
|
|
{
|
|
|
|
PRBool isBlock (PR_FALSE);
|
2001-04-07 04:45:26 +04:00
|
|
|
NodeIsBlock(node, &isBlock);
|
2001-04-06 03:48:01 +04:00
|
|
|
if (isBlock) // skip over bold, italic, link, ect nodes
|
|
|
|
{
|
|
|
|
if (IsTextNode(node) && IsEditable(node))
|
|
|
|
{
|
|
|
|
textNode = do_QueryInterface(node);
|
|
|
|
textNode->GetLength(&strLength);
|
|
|
|
if (strLength)
|
|
|
|
{
|
|
|
|
// you could use nsITextContent::IsOnlyWhitespace here
|
|
|
|
textNode->SubstringData(strLength-1,strLength,tempString);
|
|
|
|
*outIsSpace = nsCRT::IsAsciiSpace(tempString.First());
|
|
|
|
*outIsNBSP = (tempString.First() == nbsp);
|
|
|
|
if (outNode) *outNode = do_QueryInterface(aParentNode);
|
|
|
|
if (outOffset) *outOffset = strLength-1;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
// else it's an empty text node, or not editable; skip it.
|
|
|
|
}
|
|
|
|
else // node is an image or some other thingy that doesn't count as whitespace
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// otherwise we found a node we want to skip, keep going
|
|
|
|
tmp = node;
|
|
|
|
node = NextNodeInBlock(tmp, kIterBackward);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ------------ End Block methods -------------- */
|
|
|
|
|
|
|
|
|
2000-01-19 00:50:15 +03:00
|
|
|
PRBool nsHTMLEditor::IsModifiable()
|
|
|
|
{
|
|
|
|
PRUint32 flags;
|
|
|
|
if (NS_SUCCEEDED(GetFlags(&flags)))
|
|
|
|
return ((flags & eEditorReadonlyMask) == 0);
|
|
|
|
else
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
2000-03-24 03:26:47 +03:00
|
|
|
#pragma mark nsIHTMLEditor methods
|
1999-08-09 05:37:50 +04:00
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
2000-11-17 03:25:31 +03:00
|
|
|
NS_IMETHODIMP nsHTMLEditor::HandleKeyPress(nsIDOMKeyEvent* aKeyEvent)
|
1999-09-13 13:37:51 +04:00
|
|
|
{
|
|
|
|
PRUint32 keyCode, character;
|
|
|
|
PRBool isShift, ctrlKey, altKey, metaKey;
|
|
|
|
nsresult res;
|
1999-09-30 00:08:15 +04:00
|
|
|
|
1999-09-13 13:37:51 +04:00
|
|
|
if (!aKeyEvent) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(aKeyEvent->GetKeyCode(&keyCode)) &&
|
|
|
|
NS_SUCCEEDED(aKeyEvent->GetShiftKey(&isShift)) &&
|
|
|
|
NS_SUCCEEDED(aKeyEvent->GetCtrlKey(&ctrlKey)) &&
|
|
|
|
NS_SUCCEEDED(aKeyEvent->GetAltKey(&altKey)) &&
|
|
|
|
NS_SUCCEEDED(aKeyEvent->GetMetaKey(&metaKey)))
|
|
|
|
{
|
|
|
|
// this royally blows: because tabs come in from keyDowns instead
|
|
|
|
// of keyPress, and because GetCharCode refuses to work for keyDown
|
|
|
|
// i have to play games.
|
1999-11-03 10:11:45 +03:00
|
|
|
if (keyCode == nsIDOMKeyEvent::DOM_VK_TAB) character = '\t';
|
1999-09-13 13:37:51 +04:00
|
|
|
else aKeyEvent->GetCharCode(&character);
|
|
|
|
|
1999-11-03 10:11:45 +03:00
|
|
|
if (keyCode == nsIDOMKeyEvent::DOM_VK_TAB && !(mFlags&eEditorPlaintextBit))
|
1999-09-13 13:37:51 +04:00
|
|
|
{
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection>selection;
|
2000-04-19 01:39:35 +04:00
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
1999-09-13 13:37:51 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-04-19 01:39:35 +04:00
|
|
|
PRInt32 offset;
|
|
|
|
nsCOMPtr<nsIDOMNode> node, blockParent;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetStartNodeAndOffset(selection, address_of(node), &offset);
|
2000-04-19 01:39:35 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!node) return NS_ERROR_FAILURE;
|
2001-04-06 03:48:01 +04:00
|
|
|
|
|
|
|
PRBool isBlock (PR_FALSE);
|
2001-04-07 04:45:26 +04:00
|
|
|
NodeIsBlock(node, &isBlock);
|
2001-04-06 03:48:01 +04:00
|
|
|
if (isBlock) blockParent = node;
|
2000-04-19 01:39:35 +04:00
|
|
|
else blockParent = GetBlockNodeParent(node);
|
|
|
|
|
|
|
|
if (blockParent)
|
|
|
|
{
|
|
|
|
PRBool bHandled = PR_FALSE;
|
|
|
|
|
2000-08-14 03:53:34 +04:00
|
|
|
if (nsHTMLEditUtils::IsTableElement(blockParent))
|
2000-04-19 01:39:35 +04:00
|
|
|
res = TabInTable(isShift, &bHandled);
|
|
|
|
else if (nsHTMLEditUtils::IsListItem(blockParent))
|
|
|
|
{
|
|
|
|
nsAutoString indentstr;
|
2000-04-21 10:56:47 +04:00
|
|
|
if (isShift) indentstr.AssignWithConversion("outdent");
|
|
|
|
else indentstr.AssignWithConversion("indent");
|
2000-04-19 01:39:35 +04:00
|
|
|
res = Indent(indentstr);
|
|
|
|
bHandled = PR_TRUE;
|
|
|
|
}
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (bHandled) return res;
|
|
|
|
}
|
1999-09-13 13:37:51 +04:00
|
|
|
}
|
1999-11-04 01:05:45 +03:00
|
|
|
else if (keyCode == nsIDOMKeyEvent::DOM_VK_RETURN
|
|
|
|
|| keyCode == nsIDOMKeyEvent::DOM_VK_ENTER)
|
1999-09-13 13:37:51 +04:00
|
|
|
{
|
2000-11-17 03:25:31 +03:00
|
|
|
nsString empty;
|
1999-09-13 13:37:51 +04:00
|
|
|
if (isShift && !(mFlags&eEditorPlaintextBit))
|
1999-09-30 00:08:15 +04:00
|
|
|
{
|
2001-04-07 04:45:26 +04:00
|
|
|
return TypedText(empty, eTypedBR); // only inserts a br node
|
1999-09-30 00:08:15 +04:00
|
|
|
}
|
1999-09-13 13:37:51 +04:00
|
|
|
else
|
1999-10-06 23:34:09 +04:00
|
|
|
{
|
2001-04-07 04:45:26 +04:00
|
|
|
return TypedText(empty, eTypedBreak); // uses rules to figure out what to insert
|
1999-10-06 23:34:09 +04:00
|
|
|
}
|
|
|
|
}
|
2000-04-14 01:50:19 +04:00
|
|
|
else if (keyCode == nsIDOMKeyEvent::DOM_VK_ESCAPE)
|
|
|
|
{
|
|
|
|
// pass escape keypresses through as empty strings: needed forime support
|
2000-11-17 03:25:31 +03:00
|
|
|
nsString empty;
|
2001-04-07 04:45:26 +04:00
|
|
|
return TypedText(empty, eTypedText);
|
2000-04-14 01:50:19 +04:00
|
|
|
}
|
2000-01-15 17:29:29 +03:00
|
|
|
|
|
|
|
// if we got here we either fell out of the tab case or have a normal character.
|
|
|
|
// Either way, treat as normal character.
|
|
|
|
if (character && !altKey && !ctrlKey && !isShift && !metaKey)
|
landing keyEvent_19991004_BRANCH
bugs # see the log of the check in into branch
author/reviewer:
mozilla/layout/base/src/nsRangeList.cpp brade/mjudge
mozilla/layout/html/forms/src/nsGfxTextControlFrame.cpp brade/ftang
mozilla/layout/events/src/nsDOMEvent.cpp brade/joki
mozilla/layout/events/src/nsEventStateManager.cpp brade/joki
mozilla/widget/public/nsGUIEvent.h akkana/ftang
mozilla/widget/src/windows/nsWindow.cpp ftang/mjudge
mozilla/widget/src/windows/nsWindow.h ftang/mjudge
mozilla/widget/src/mac/nsTextAreaWidget.cpp brade/ftang
mozilla/widget/src/mac/nsMacEventHandler.cpp brade/simon
mozilla/widget/src/xpwidgets/nsKeyBindMgr.cpp brade/ftang
mozilla/widget/src/gtk/nsGtkEventHandler.cpp akkana/?
mozilla/widget/src/gtk/nsWidget.cpp erik/ftang
mozilla/layout/xul/base/src/nsTreeCellFrame.cpp brade/ftang
mozilla/editor/base/nsEditorEventListeners.cpp brade/akkana
mozilla/editor/base/nsHTMLEditor.cpp brade/akkana
mozilla/rdf/content/src/nsXULKeyListener.cpp ftang/saari
fix the master bug- 15693
fix at least, but not limited to, the following bugs
10158,11956,6053,9333,10901,14348,6449,11845,13016,14410,15657,15307,15842,13856
1999-10-14 22:27:01 +04:00
|
|
|
{
|
2000-01-15 17:29:29 +03:00
|
|
|
nsAutoString key(character);
|
2001-04-07 04:45:26 +04:00
|
|
|
return TypedText(key, eTypedText);
|
1999-09-13 13:37:51 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
1999-10-06 23:34:09 +04:00
|
|
|
/* This routine is needed to provide a bottleneck for typing for logging
|
|
|
|
purposes. Can't use EditorKeyPress() (above) for that since it takes
|
|
|
|
a nsIDOMUIEvent* parameter. So instead we pass enough info through
|
|
|
|
to TypedText() to determine what action to take, but without passing
|
|
|
|
an event.
|
|
|
|
*/
|
2001-04-07 04:45:26 +04:00
|
|
|
NS_IMETHODIMP nsHTMLEditor::TypedText(const nsAReadableString& aString,
|
2000-11-17 03:25:31 +03:00
|
|
|
PRInt32 aAction)
|
1999-10-06 23:34:09 +04:00
|
|
|
{
|
|
|
|
nsAutoPlaceHolderBatch batch(this, gTypingTxnName);
|
|
|
|
|
|
|
|
switch (aAction)
|
|
|
|
{
|
|
|
|
case eTypedText:
|
2001-01-28 23:13:07 +03:00
|
|
|
case eTypedBreak:
|
1999-10-06 23:34:09 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
return nsPlaintextEditor::TypedText(aString, aAction);
|
1999-10-06 23:34:09 +04:00
|
|
|
}
|
|
|
|
case eTypedBR:
|
2000-01-15 17:29:29 +03:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> brNode;
|
2000-12-09 07:46:08 +03:00
|
|
|
return InsertBR(address_of(brNode)); // only inserts a br node
|
2000-01-15 17:29:29 +03:00
|
|
|
}
|
1999-10-06 23:34:09 +04:00
|
|
|
}
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
1999-09-13 13:37:51 +04:00
|
|
|
NS_IMETHODIMP nsHTMLEditor::TabInTable(PRBool inIsShift, PRBool *outHandled)
|
|
|
|
{
|
|
|
|
if (!outHandled) return NS_ERROR_NULL_POINTER;
|
|
|
|
*outHandled = PR_FALSE;
|
|
|
|
|
2000-04-04 18:51:26 +04:00
|
|
|
// Find enclosing table cell from the selection (cell may be the selected element)
|
|
|
|
nsCOMPtr<nsIDOMElement> cellElement;
|
2000-08-20 04:34:08 +04:00
|
|
|
// can't use |NS_LITERAL_STRING| here until |GetElementOrParentByTagName| is fixed to accept readables
|
|
|
|
nsresult res = GetElementOrParentByTagName(NS_ConvertASCIItoUCS2("td"), nsnull, getter_AddRefs(cellElement));
|
1999-09-13 13:37:51 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-04-04 18:51:26 +04:00
|
|
|
// Do nothing -- we didn't find a table cell
|
|
|
|
if (!cellElement) return NS_OK;
|
|
|
|
|
|
|
|
// find enclosing table
|
|
|
|
nsCOMPtr<nsIDOMNode> tbl = GetEnclosingTable(cellElement);
|
|
|
|
if (!tbl) return res;
|
|
|
|
|
|
|
|
// advance to next cell
|
|
|
|
// first create an iterator over the table
|
|
|
|
nsCOMPtr<nsIContentIterator> iter;
|
|
|
|
res = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
|
|
|
|
NS_GET_IID(nsIContentIterator),
|
|
|
|
getter_AddRefs(iter));
|
1999-09-13 13:37:51 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-04-04 18:51:26 +04:00
|
|
|
if (!iter) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsCOMPtr<nsIContent> cTbl = do_QueryInterface(tbl);
|
|
|
|
nsCOMPtr<nsIContent> cBlock = do_QueryInterface(cellElement);
|
|
|
|
res = iter->Init(cTbl);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// position iter at block
|
|
|
|
res = iter->PositionAt(cBlock);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
nsCOMPtr<nsIContent> cNode;
|
|
|
|
do
|
1999-09-13 13:37:51 +04:00
|
|
|
{
|
2000-04-04 18:51:26 +04:00
|
|
|
if (inIsShift) res = iter->Prev();
|
|
|
|
else res = iter->Next();
|
2000-04-19 01:39:35 +04:00
|
|
|
if (NS_FAILED(res)) break;
|
2000-04-04 18:51:26 +04:00
|
|
|
res = iter->CurrentNode(getter_AddRefs(cNode));
|
2000-04-19 01:39:35 +04:00
|
|
|
if (NS_FAILED(res)) break;
|
2000-04-04 18:51:26 +04:00
|
|
|
node = do_QueryInterface(cNode);
|
2000-08-14 03:53:34 +04:00
|
|
|
if (nsHTMLEditUtils::IsTableCell(node) && (GetEnclosingTable(node) == tbl))
|
1999-09-13 13:37:51 +04:00
|
|
|
{
|
2000-04-04 18:51:26 +04:00
|
|
|
res = CollapseSelectionToDeepestNonTableFirstChild(nsnull, node);
|
1999-09-13 13:37:51 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-04-04 18:51:26 +04:00
|
|
|
*outHandled = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
} while (iter->IsDone() == NS_ENUMERATOR_FALSE);
|
2000-04-19 01:39:35 +04:00
|
|
|
|
|
|
|
if (!(*outHandled) && !inIsShift)
|
|
|
|
{
|
|
|
|
// if we havent handled it yet then we must have run off the end of
|
|
|
|
// the table. Insert a new row.
|
|
|
|
res = InsertTableRow(1, PR_TRUE);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
*outHandled = PR_TRUE;
|
|
|
|
// put selection in right place
|
2000-05-02 07:24:11 +04:00
|
|
|
// Use table code to get selection and index to new row...
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection>selection;
|
2000-05-04 01:18:23 +04:00
|
|
|
nsCOMPtr<nsIDOMElement> tblElement;
|
2000-04-19 01:39:35 +04:00
|
|
|
nsCOMPtr<nsIDOMElement> cell;
|
2000-05-02 07:24:11 +04:00
|
|
|
PRInt32 row;
|
|
|
|
res = GetCellContext(getter_AddRefs(selection),
|
2000-05-04 01:18:23 +04:00
|
|
|
getter_AddRefs(tblElement),
|
2000-05-02 07:24:11 +04:00
|
|
|
getter_AddRefs(cell),
|
|
|
|
nsnull, nsnull,
|
|
|
|
&row, nsnull);
|
2000-04-19 01:39:35 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-05-02 07:24:11 +04:00
|
|
|
// ...so that we can ask for first cell in that row...
|
2001-02-27 01:02:58 +03:00
|
|
|
res = GetCellAt(tblElement, row, 0, getter_AddRefs(cell));
|
2000-04-19 01:39:35 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-05-02 07:24:11 +04:00
|
|
|
// ...and then set selection there.
|
|
|
|
// (Note that normally you should use CollapseSelectionToDeepestNonTableFirstChild(),
|
|
|
|
// but we know cell is an empty new cell, so this works fine)
|
2000-04-19 01:39:35 +04:00
|
|
|
node = do_QueryInterface(cell);
|
|
|
|
if (node) selection->Collapse(node,0);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
1999-09-13 13:37:51 +04:00
|
|
|
}
|
|
|
|
|
2000-04-14 01:50:19 +04:00
|
|
|
NS_IMETHODIMP nsHTMLEditor::CreateBRImpl(nsCOMPtr<nsIDOMNode> *aInOutParent, PRInt32 *aInOutOffset, nsCOMPtr<nsIDOMNode> *outBRNode, EDirection aSelect)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
if (!aInOutParent || !*aInOutParent || !aInOutOffset || !outBRNode) return NS_ERROR_NULL_POINTER;
|
1999-11-25 03:19:45 +03:00
|
|
|
*outBRNode = nsnull;
|
|
|
|
nsresult res;
|
|
|
|
|
|
|
|
// we need to insert a br. unfortunately, we may have to split a text node to do it.
|
2000-03-24 03:26:47 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> node = *aInOutParent;
|
|
|
|
PRInt32 theOffset = *aInOutOffset;
|
|
|
|
nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(node);
|
2000-04-18 11:44:58 +04:00
|
|
|
nsAutoString brType; brType.AssignWithConversion("br");
|
1999-11-25 03:19:45 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> brNode;
|
|
|
|
if (nodeAsText)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> tmp;
|
|
|
|
PRInt32 offset;
|
|
|
|
PRUint32 len;
|
|
|
|
nodeAsText->GetLength(&len);
|
2000-12-09 07:46:08 +03:00
|
|
|
GetNodeLocation(node, address_of(tmp), &offset);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (!tmp) return NS_ERROR_FAILURE;
|
2000-03-24 03:26:47 +03:00
|
|
|
if (!theOffset)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
// we are already set to go
|
|
|
|
}
|
2000-03-24 03:26:47 +03:00
|
|
|
else if (theOffset == (PRInt32)len)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
// update offset to point AFTER the text node
|
|
|
|
offset++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// split the text node
|
2000-03-24 03:26:47 +03:00
|
|
|
res = SplitNode(node, theOffset, getter_AddRefs(tmp));
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetNodeLocation(node, address_of(tmp), &offset);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
// create br
|
|
|
|
res = CreateNode(brType, tmp, offset, getter_AddRefs(brNode));
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
*aInOutParent = tmp;
|
|
|
|
*aInOutOffset = offset+1;
|
1999-11-25 03:19:45 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
res = CreateNode(brType, node, theOffset, getter_AddRefs(brNode));
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
(*aInOutOffset)++;
|
1999-11-25 03:19:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
*outBRNode = brNode;
|
2000-02-25 07:39:30 +03:00
|
|
|
if (*outBRNode && (aSelect != eNone))
|
|
|
|
{
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
2000-02-25 07:39:30 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
PRInt32 offset;
|
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetNodeLocation(*outBRNode, address_of(parent), &offset);
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (aSelect == eNext)
|
|
|
|
{
|
|
|
|
// position selection after br
|
2000-09-14 15:45:01 +04:00
|
|
|
selPriv->SetInterlinePosition(PR_TRUE);
|
2000-02-25 07:39:30 +03:00
|
|
|
res = selection->Collapse(parent, offset+1);
|
|
|
|
}
|
|
|
|
else if (aSelect == ePrevious)
|
|
|
|
{
|
|
|
|
// position selection before br
|
2000-09-14 15:45:01 +04:00
|
|
|
selPriv->SetInterlinePosition(PR_TRUE);
|
2000-02-25 07:39:30 +03:00
|
|
|
res = selection->Collapse(parent, offset);
|
|
|
|
}
|
|
|
|
}
|
1999-11-25 03:19:45 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
|
|
|
|
NS_IMETHODIMP nsHTMLEditor::CreateBR(nsIDOMNode *aNode, PRInt32 aOffset, nsCOMPtr<nsIDOMNode> *outBRNode, EDirection aSelect)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> parent = aNode;
|
|
|
|
PRInt32 offset = aOffset;
|
2000-12-09 07:46:08 +03:00
|
|
|
return CreateBRImpl(address_of(parent), &offset, outBRNode, aSelect);
|
2000-03-24 03:26:47 +03:00
|
|
|
}
|
|
|
|
|
1999-09-30 00:08:15 +04:00
|
|
|
NS_IMETHODIMP nsHTMLEditor::InsertBR(nsCOMPtr<nsIDOMNode> *outBRNode)
|
1999-09-13 13:37:51 +04:00
|
|
|
{
|
|
|
|
PRBool bCollapsed;
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
1999-09-13 13:37:51 +04:00
|
|
|
|
1999-09-30 00:08:15 +04:00
|
|
|
if (!outBRNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
*outBRNode = nsnull;
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
|
|
|
|
// calling it text insertion to trigger moz br treatment by rules
|
|
|
|
nsAutoRules beginRulesSniffing(this, kOpInsertText, nsIEditor::eNext);
|
|
|
|
|
1999-09-13 13:37:51 +04:00
|
|
|
nsresult res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
|
1999-09-13 13:37:51 +04:00
|
|
|
res = selection->GetIsCollapsed(&bCollapsed);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!bCollapsed)
|
|
|
|
{
|
1999-12-07 11:30:19 +03:00
|
|
|
res = DeleteSelection(nsIEditor::eNone);
|
1999-09-13 13:37:51 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIDOMNode> selNode;
|
|
|
|
PRInt32 selOffset;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetStartNodeAndOffset(selection, address_of(selNode), &selOffset);
|
1999-09-13 13:37:51 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
res = CreateBR(selNode, selOffset, outBRNode);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2000-02-25 07:39:30 +03:00
|
|
|
// position selection after br
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetNodeLocation(*outBRNode, address_of(selNode), &selOffset);
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-09-14 15:45:01 +04:00
|
|
|
selPriv->SetInterlinePosition(PR_TRUE);
|
2000-02-25 07:39:30 +03:00
|
|
|
res = selection->Collapse(selNode, selOffset+1);
|
|
|
|
|
|
|
|
return res;
|
1999-09-13 13:37:51 +04:00
|
|
|
}
|
1999-08-09 05:37:50 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::GetDOMEventReceiver(nsIDOMEventReceiver **aEventReceiver)
|
|
|
|
{
|
|
|
|
if (!aEventReceiver)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
1999-03-01 22:54:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
*aEventReceiver = 0;
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMElement> rootElement;
|
1999-08-19 17:30:48 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult result = GetRootElement(getter_AddRefs(rootElement));
|
1999-08-19 17:30:48 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (NS_FAILED(result))
|
|
|
|
return result;
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!rootElement)
|
|
|
|
return NS_ERROR_FAILURE;
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Now hack to make sure we are not anonymous content.
|
|
|
|
// If we are grab the parent of root element for our observer.
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(rootElement);
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (content)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> parent;
|
|
|
|
if (NS_SUCCEEDED(content->GetParent(*getter_AddRefs(parent))) && parent)
|
|
|
|
{
|
|
|
|
PRInt32 index;
|
|
|
|
if (NS_FAILED(parent->IndexOf(content, index)) || index < 0 )
|
|
|
|
{
|
|
|
|
rootElement = do_QueryInterface(parent); //this will put listener on the form element basically
|
|
|
|
result = rootElement->QueryInterface(NS_GET_IID(nsIDOMEventReceiver), (void **)aEventReceiver);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rootElement = 0; // Let the event receiver work on the document instead of the root element
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rootElement = 0;
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!rootElement && mDocWeak)
|
|
|
|
{
|
|
|
|
// Don't use getDocument here, because we have no way of knowing if
|
|
|
|
// Init() was ever called. So we need to get the document ourselves,
|
|
|
|
// if it exists.
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMDocument> domdoc = do_QueryReferent(mDocWeak);
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!domdoc)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
result = domdoc->QueryInterface(NS_GET_IID(nsIDOMEventReceiver), (void **)aEventReceiver);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::CollapseSelectionToStart()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMElement> bodyElement;
|
|
|
|
nsresult res = nsEditor::GetRootElement(getter_AddRefs(bodyElement));
|
2000-03-24 03:26:47 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!bodyElement) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsCOMPtr<nsIDOMNode> bodyNode = do_QueryInterface(bodyElement);
|
|
|
|
return CollapseSelectionToDeepestNonTableFirstChild(nsnull, bodyNode);
|
2000-03-24 03:26:47 +03:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::CollapseSelectionToDeepestNonTableFirstChild(nsISelection *aSelection, nsIDOMNode *aNode)
|
2000-03-24 03:26:47 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!aNode) return NS_ERROR_NULL_POINTER;
|
2000-03-24 03:26:47 +03:00
|
|
|
nsresult res;
|
2001-01-28 23:13:07 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
|
|
if (aSelection)
|
2000-03-24 03:26:47 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
selection = aSelection;
|
|
|
|
} else {
|
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!selection) return NS_ERROR_FAILURE;
|
2000-03-24 03:26:47 +03:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> node = aNode;
|
|
|
|
nsCOMPtr<nsIDOMNode> child;
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
do {
|
|
|
|
node->GetFirstChild(getter_AddRefs(child));
|
|
|
|
|
|
|
|
if (child)
|
2000-03-24 03:26:47 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
// Stop if we find a table
|
|
|
|
// don't want to go into nested tables
|
|
|
|
if (nsHTMLEditUtils::IsTable(child)) break;
|
|
|
|
// hey, it'g gotta be a container too!
|
|
|
|
if (!IsContainer(child)) break;
|
|
|
|
node = child;
|
2000-03-24 03:26:47 +03:00
|
|
|
}
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
while (child);
|
|
|
|
|
|
|
|
selection->Collapse(node,0);
|
2000-03-24 03:26:47 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-04-14 01:50:19 +04:00
|
|
|
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// This is mostly like InsertHTMLWithCharset,
|
|
|
|
// but we can't use that because it is selection-based and
|
|
|
|
// the rules code won't let us edit under the <head> node
|
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::ReplaceHeadContentsWithHTML(const nsAReadableString& aSourceToInsert)
|
2000-03-24 03:26:47 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
|
|
nsresult res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!selection) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
ForceCompositionEnd();
|
|
|
|
|
|
|
|
// Do not use nsAutoRules -- rules code won't let us insert in <head>
|
|
|
|
// Use the head node as a parent and delete/insert directly
|
|
|
|
nsCOMPtr<nsIDOMNodeList>nodeList;
|
|
|
|
nsAutoString headTag; headTag.AssignWithConversion("head");
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(mDocWeak);
|
|
|
|
if (!doc) return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
res = doc->GetElementsByTagName(headTag, getter_AddRefs(nodeList));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!nodeList) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
PRUint32 count;
|
|
|
|
nodeList->GetLength(&count);
|
|
|
|
if (count < 1) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> headNode;
|
|
|
|
res = nodeList->Item(0, getter_AddRefs(headNode));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!headNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// First, make sure there are no return chars in the source.
|
|
|
|
// Bad things happen if you insert returns (instead of dom newlines, \n)
|
|
|
|
// into an editor document.
|
|
|
|
nsAutoString inputString (aSourceToInsert); // hope this does copy-on-write
|
|
|
|
|
|
|
|
// Windows linebreaks: Map CRLF to LF:
|
|
|
|
inputString.ReplaceSubstring(NS_ConvertASCIItoUCS2("\r\n"),
|
|
|
|
NS_ConvertASCIItoUCS2("\n"));
|
|
|
|
|
|
|
|
// Mac linebreaks: Map any remaining CR to LF:
|
|
|
|
inputString.ReplaceSubstring(NS_ConvertASCIItoUCS2("\r"),
|
|
|
|
NS_ConvertASCIItoUCS2("\n"));
|
|
|
|
|
|
|
|
nsAutoEditBatch beginBatching(this);
|
|
|
|
|
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!selection) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// Get the first range in the selection, for context:
|
|
|
|
nsCOMPtr<nsIDOMRange> range;
|
|
|
|
res = selection->GetRangeAt(0, getter_AddRefs(range));
|
|
|
|
if (NS_FAILED(res))
|
|
|
|
return res;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNSRange> nsrange (do_QueryInterface(range));
|
|
|
|
if (!nsrange)
|
|
|
|
return NS_ERROR_NO_INTERFACE;
|
|
|
|
nsCOMPtr<nsIDOMDocumentFragment> docfrag;
|
|
|
|
res = nsrange->CreateContextualFragment(inputString,
|
|
|
|
getter_AddRefs(docfrag));
|
|
|
|
|
|
|
|
//XXXX BUG 50965: This is not returning the text between <title> ... </title>
|
|
|
|
// Special code is needed in JS to handle title anyway, so it really doesn't matter!
|
2000-04-14 07:19:31 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (NS_FAILED(res))
|
2000-03-24 03:26:47 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
printf("Couldn't create contextual fragment: error was %d\n", res);
|
|
|
|
#endif
|
|
|
|
return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!docfrag) return NS_ERROR_NULL_POINTER;
|
2000-04-14 07:19:31 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> child;
|
|
|
|
|
|
|
|
// First delete all children in head
|
|
|
|
do {
|
|
|
|
res = headNode->GetFirstChild(getter_AddRefs(child));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (child)
|
2000-03-24 03:26:47 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = DeleteNode(child);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
} while (child);
|
|
|
|
|
|
|
|
// Now insert the new nodes
|
|
|
|
PRInt32 offsetOfNewNode = 0;
|
|
|
|
nsCOMPtr<nsIDOMNode> fragmentAsNode (do_QueryInterface(docfrag));
|
|
|
|
|
|
|
|
// Loop over the contents of the fragment and move into the document
|
|
|
|
do {
|
|
|
|
res = fragmentAsNode->GetFirstChild(getter_AddRefs(child));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (child)
|
2000-03-24 03:26:47 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = InsertNode(child, headNode, offsetOfNewNode++);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
} while (child);
|
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::RebuildDocumentFromSource(const nsAReadableString& aSourceString)
|
2000-03-24 03:26:47 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
ForceCompositionEnd();
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsISelection>selection;
|
|
|
|
nsresult res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMElement> bodyElement;
|
|
|
|
res = GetRootElement(getter_AddRefs(bodyElement));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!bodyElement) return NS_ERROR_NULL_POINTER;
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Find where the <body> tag starts.
|
|
|
|
// If user mangled that, then abort
|
2001-04-07 04:45:26 +04:00
|
|
|
nsReadingIterator<PRUnichar> beginbody;
|
|
|
|
nsReadingIterator<PRUnichar> endbody;
|
|
|
|
aSourceString.BeginReading(beginbody);
|
|
|
|
aSourceString.EndReading(endbody);
|
|
|
|
if (!FindInReadable(NS_LITERAL_STRING("<body"),beginbody,endbody))
|
|
|
|
return NS_ERROR_FAILURE;
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-04-07 04:45:26 +04:00
|
|
|
nsReadingIterator<PRUnichar> beginhead;
|
|
|
|
nsReadingIterator<PRUnichar> endhead;
|
|
|
|
aSourceString.BeginReading(beginhead);
|
|
|
|
aSourceString.EndReading(endhead);
|
|
|
|
if (!FindInReadable(NS_LITERAL_STRING("<head"),beginhead,endhead))
|
|
|
|
return NS_ERROR_FAILURE;
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-04-07 04:45:26 +04:00
|
|
|
nsReadingIterator<PRUnichar> beginclosehead;
|
|
|
|
nsReadingIterator<PRUnichar> endclosehead;
|
|
|
|
aSourceString.BeginReading(beginclosehead);
|
|
|
|
aSourceString.EndReading(endclosehead);
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-04-07 04:45:26 +04:00
|
|
|
// Find the index after "<head>"
|
|
|
|
if (!FindInReadable(NS_LITERAL_STRING("</head"),beginclosehead,endclosehead))
|
|
|
|
beginclosehead = beginbody;
|
2001-01-28 23:13:07 +03:00
|
|
|
// We'll be forgiving and assume head ends before body
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Time to change the document
|
|
|
|
nsAutoEditBatch beginBatching(this);
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Try to replace body contents first
|
|
|
|
res = SelectAll();
|
2000-03-24 03:26:47 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
|
2001-04-07 04:45:26 +04:00
|
|
|
nsReadingIterator<PRUnichar> endtotal;
|
|
|
|
aSourceString.EndReading(endtotal);
|
|
|
|
|
|
|
|
res = InsertHTML(Substring(beginbody,endtotal));
|
2000-03-24 03:26:47 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
selection->Collapse(bodyElement, 0);
|
|
|
|
|
2001-04-07 04:45:26 +04:00
|
|
|
res = ReplaceHeadContentsWithHTML(Substring(beginhead,beginclosehead));
|
2000-03-24 03:26:47 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
|
|
|
|
// Now we must copy attributes user might have edited on the <body> tag
|
|
|
|
// because InsertHTML (actually, CreateContextualFragment())
|
|
|
|
// will never return a body node in the DOM fragment
|
2001-04-10 07:02:10 +04:00
|
|
|
|
|
|
|
// We already know where "<body" begins
|
|
|
|
nsReadingIterator<PRUnichar> beginclosebody = beginbody;
|
2001-04-07 04:45:26 +04:00
|
|
|
nsReadingIterator<PRUnichar> endclosebody;
|
|
|
|
aSourceString.EndReading(endclosebody);
|
|
|
|
if (!FindInReadable(NS_LITERAL_STRING(">"),beginclosebody,endclosebody))
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nsAutoString bodyTag(Substring(beginbody,endclosebody));//<bodyXXXX >
|
2001-01-28 23:13:07 +03:00
|
|
|
// Truncate at the end of the body tag
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Kludge of the year: fool the parser by replacing "body" with "div" so we get a node
|
2001-04-07 04:45:26 +04:00
|
|
|
bodyTag.ReplaceSubstring(NS_ConvertASCIItoUCS2("body"), NS_ConvertASCIItoUCS2("div"));
|
2001-01-28 23:13:07 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMRange> range;
|
|
|
|
res = selection->GetRangeAt(0, getter_AddRefs(range));
|
2000-03-24 03:26:47 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMNSRange> nsrange (do_QueryInterface(range));
|
|
|
|
if (!nsrange) return NS_ERROR_NO_INTERFACE;
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMDocumentFragment> docfrag;
|
2001-04-07 04:45:26 +04:00
|
|
|
res = nsrange->CreateContextualFragment(bodyTag, getter_AddRefs(docfrag));
|
2001-01-28 23:13:07 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-03-01 22:54:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> fragmentAsNode (do_QueryInterface(docfrag));
|
|
|
|
if (!fragmentAsNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> child;
|
|
|
|
res = fragmentAsNode->GetFirstChild(getter_AddRefs(child));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!child) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// Copy all attributes from the div child to current body element
|
|
|
|
return CloneAttributes(bodyElement, child);
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::InsertElementAtSelection(nsIDOMElement* aElement, PRBool aDeleteSelection)
|
1999-03-01 22:54:47 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res = NS_ERROR_NOT_INITIALIZED;
|
|
|
|
|
|
|
|
if (!aElement)
|
1999-08-09 05:37:50 +04:00
|
|
|
return NS_ERROR_NULL_POINTER;
|
2001-01-28 23:13:07 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aElement);
|
|
|
|
|
|
|
|
ForceCompositionEnd();
|
|
|
|
nsAutoEditBatch beginBatching(this);
|
|
|
|
nsAutoRules beginRulesSniffing(this, kOpInsertElement, nsIEditor::eNext);
|
|
|
|
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection>selection;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (!NS_SUCCEEDED(res) || !selection)
|
|
|
|
return NS_ERROR_FAILURE;
|
1999-08-19 17:30:48 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// hand off to the rules system, see if it has anything to say about this
|
|
|
|
PRBool cancel, handled;
|
|
|
|
nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertElement);
|
|
|
|
ruleInfo.insertElement = aElement;
|
|
|
|
res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
|
|
|
|
if (cancel || (NS_FAILED(res))) return res;
|
1999-08-19 17:30:48 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!handled)
|
1999-08-09 05:37:50 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
if (aDeleteSelection)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> tempNode;
|
|
|
|
PRInt32 tempOffset;
|
|
|
|
nsresult result = DeleteSelectionAndPrepareToCreateNode(tempNode,tempOffset);
|
|
|
|
if (!NS_SUCCEEDED(result))
|
|
|
|
return result;
|
|
|
|
}
|
2000-01-31 13:30:12 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// If deleting, selection will be collapsed.
|
|
|
|
// so if not, we collapse it
|
|
|
|
if (!aDeleteSelection)
|
2000-01-31 13:30:12 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
// Named Anchor is a special case,
|
|
|
|
// We collapse to insert element BEFORE the selection
|
|
|
|
// For all other tags, we insert AFTER the selection
|
|
|
|
if (nsHTMLEditUtils::IsNamedAnchor(node))
|
2000-01-31 13:30:12 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
selection->CollapseToStart();
|
|
|
|
} else {
|
|
|
|
selection->CollapseToEnd();
|
2000-01-31 13:30:12 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> parentSelectedNode;
|
|
|
|
PRInt32 offsetForInsert;
|
|
|
|
res = selection->GetAnchorNode(getter_AddRefs(parentSelectedNode));
|
|
|
|
// XXX: ERROR_HANDLING bad XPCOM usage
|
|
|
|
if (NS_SUCCEEDED(res) && NS_SUCCEEDED(selection->GetAnchorOffset(&offsetForInsert)) && parentSelectedNode)
|
1999-08-09 05:37:50 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
#ifdef DEBUG_cmanske
|
1999-08-19 17:30:48 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoString name;
|
|
|
|
parentSelectedNode->GetNodeName(name);
|
|
|
|
printf("InsertElement: Anchor node of selection: ");
|
|
|
|
wprintf(name.GetUnicode());
|
|
|
|
printf(" Offset: %d\n", offsetForInsert);
|
1999-08-09 05:37:50 +04:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
#endif
|
1999-03-01 22:54:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
res = InsertNodeAtPoint(node, parentSelectedNode, offsetForInsert, PR_FALSE);
|
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
|
|
|
// Set caret after element, but check for special case
|
|
|
|
// of inserting table-related elements: set in first cell instead
|
|
|
|
if (!SetCaretInTableCell(aElement))
|
|
|
|
res = SetCaretAfterElement(aElement);
|
2000-04-14 01:50:19 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
res = mRules->DidDoAction(selection, &ruleInfo, res);
|
|
|
|
return res;
|
2000-04-14 01:50:19 +04:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::InsertNodeAtPoint(nsIDOMNode *aNode,
|
|
|
|
nsIDOMNode *aParent,
|
|
|
|
PRInt32 aOffset,
|
|
|
|
PRBool aNoEmptyNodes)
|
1999-05-27 01:40:51 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
|
|
|
|
NS_ENSURE_TRUE(aParent, NS_ERROR_NULL_POINTER);
|
|
|
|
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
nsAutoString tagName;
|
|
|
|
aNode->GetNodeName(tagName);
|
|
|
|
tagName.ToLowerCase();
|
|
|
|
nsCOMPtr<nsIDOMNode> parent = aParent;
|
|
|
|
nsCOMPtr<nsIDOMNode> topChild = aParent;
|
|
|
|
nsCOMPtr<nsIDOMNode> tmp;
|
|
|
|
PRInt32 offsetOfInsert = aOffset;
|
|
|
|
|
|
|
|
// Search up the parent chain to find a suitable container
|
|
|
|
while (!CanContainTag(parent, tagName))
|
|
|
|
{
|
|
|
|
// If the current parent is a root (body or table element)
|
|
|
|
// then go no further - we can't insert
|
2001-04-06 03:48:01 +04:00
|
|
|
if (nsTextEditUtils::IsBody(parent) || nsHTMLEditUtils::IsTableElement(parent))
|
2001-01-28 23:13:07 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
// Get the next parent
|
|
|
|
parent->GetParentNode(getter_AddRefs(tmp));
|
|
|
|
NS_ENSURE_TRUE(tmp, NS_ERROR_FAILURE);
|
|
|
|
topChild = parent;
|
|
|
|
parent = tmp;
|
|
|
|
}
|
|
|
|
if (parent != topChild)
|
|
|
|
{
|
|
|
|
// we need to split some levels above the original selection parent
|
|
|
|
res = SplitNodeDeep(topChild, aParent, aOffset, &offsetOfInsert, aNoEmptyNodes);
|
|
|
|
if (NS_FAILED(res))
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
// Now we can insert the new node
|
|
|
|
res = InsertNode(aNode, parent, offsetOfInsert);
|
|
|
|
return res;
|
2000-04-14 01:50:19 +04:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::SelectElement(nsIDOMElement* aElement)
|
2000-04-14 01:50:19 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res = NS_ERROR_NULL_POINTER;
|
2000-04-14 07:19:31 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Must be sure that element is contained in the document body
|
|
|
|
if (IsElementInBody(aElement))
|
1999-08-09 05:37:50 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
2000-03-29 16:53:23 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!selection) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsCOMPtr<nsIDOMNode>parent;
|
|
|
|
res = aElement->GetParentNode(getter_AddRefs(parent));
|
|
|
|
if (NS_SUCCEEDED(res) && parent)
|
1999-08-19 17:30:48 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
PRInt32 offsetInParent;
|
|
|
|
res = GetChildOffset(aElement, parent, offsetInParent);
|
1999-08-19 17:30:48 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (NS_SUCCEEDED(res))
|
|
|
|
{
|
|
|
|
// Collapse selection to just before desired element,
|
|
|
|
res = selection->Collapse(parent, offsetInParent);
|
|
|
|
if (NS_SUCCEEDED(res)) {
|
|
|
|
// then extend it to just after
|
|
|
|
res = selection->Extend(parent, offsetInParent+1);
|
2000-03-24 03:26:47 +03:00
|
|
|
}
|
1999-08-19 17:30:48 +04:00
|
|
|
}
|
1999-08-09 05:37:50 +04:00
|
|
|
}
|
1999-10-06 23:34:09 +04:00
|
|
|
}
|
2000-03-24 03:26:47 +03:00
|
|
|
return res;
|
1999-05-27 01:40:51 +04:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::SetCaretAfterElement(nsIDOMElement* aElement)
|
1999-11-13 19:37:58 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res = NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// Be sure the element is contained in the document body
|
|
|
|
if (aElement && IsElementInBody(aElement))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!selection) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsCOMPtr<nsIDOMNode>parent;
|
|
|
|
res = aElement->GetParentNode(getter_AddRefs(parent));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!parent) return NS_ERROR_NULL_POINTER;
|
|
|
|
PRInt32 offsetInParent;
|
|
|
|
res = GetChildOffset(aElement, parent, offsetInParent);
|
|
|
|
if (NS_SUCCEEDED(res))
|
|
|
|
{
|
|
|
|
// Collapse selection to just after desired element,
|
|
|
|
res = selection->Collapse(parent, offsetInParent+1);
|
|
|
|
#if 0 //def DEBUG_cmanske
|
|
|
|
{
|
|
|
|
nsAutoString name;
|
|
|
|
parent->GetNodeName(name);
|
|
|
|
printf("SetCaretAfterElement: Parent node: ");
|
|
|
|
wprintf(name.GetUnicode());
|
|
|
|
printf(" Offset: %d\n\nHTML:\n", offsetInParent+1);
|
|
|
|
nsAutoString Format("text/html");
|
|
|
|
nsAutoString ContentsAs;
|
|
|
|
OutputToString(ContentsAs, Format, 2);
|
|
|
|
wprintf(ContentsAs.GetUnicode());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
1999-11-13 19:37:58 +03:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::SetParagraphFormat(const nsAReadableString& aParagraphFormat)
|
1999-11-13 19:37:58 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoString tag; tag.Assign(aParagraphFormat);
|
|
|
|
tag.ToLowerCase();
|
|
|
|
if (tag.EqualsWithConversion("dd") || tag.EqualsWithConversion("dt"))
|
|
|
|
return MakeDefinitionItem(tag);
|
|
|
|
else
|
|
|
|
return InsertBasicBlock(tag);
|
1999-11-13 19:37:58 +03:00
|
|
|
}
|
1999-09-22 05:21:56 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// XXX: ERROR_HANDLING -- this method needs a little work to ensure all error codes are
|
|
|
|
// checked properly, all null pointers are checked, and no memory leaks occur
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::GetParentBlockTags(nsStringArray *aTagList, PRBool aGetLists)
|
1999-09-22 05:21:56 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!aTagList) { return NS_ERROR_NULL_POINTER; }
|
2000-03-29 16:53:23 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res;
|
|
|
|
nsCOMPtr<nsISelection>selection;
|
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!selection) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
|
|
|
|
|
|
|
|
// Find out if the selection is collapsed:
|
|
|
|
PRBool isCollapsed;
|
|
|
|
res = selection->GetIsCollapsed(&isCollapsed);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (isCollapsed)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> node, blockParent;
|
|
|
|
PRInt32 offset;
|
|
|
|
|
|
|
|
res = GetStartNodeAndOffset(selection, address_of(node), &offset);
|
|
|
|
if (!node) res = NS_ERROR_FAILURE;
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMElement> blockParentElem;
|
|
|
|
if (aGetLists)
|
|
|
|
{
|
|
|
|
// Get the "ol", "ul", or "dl" parent element
|
|
|
|
res = GetElementOrParentByTagName(NS_ConvertASCIItoUCS2("list"), node, getter_AddRefs(blockParentElem));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-04-06 03:48:01 +04:00
|
|
|
PRBool isBlock (PR_FALSE);
|
2001-04-07 04:45:26 +04:00
|
|
|
NodeIsBlock(node, &isBlock);
|
2001-04-06 03:48:01 +04:00
|
|
|
if (isBlock) blockParent = node;
|
2001-01-28 23:13:07 +03:00
|
|
|
else blockParent = GetBlockNodeParent(node);
|
|
|
|
blockParentElem = do_QueryInterface(blockParent);
|
|
|
|
}
|
|
|
|
if (blockParentElem)
|
|
|
|
{
|
|
|
|
nsAutoString blockParentTag;
|
|
|
|
blockParentElem->GetTagName(blockParentTag);
|
|
|
|
aTagList->AppendString(blockParentTag);
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// else non-collapsed selection
|
2000-03-29 16:53:23 +04:00
|
|
|
nsCOMPtr<nsIEnumerator> enumerator;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-29 16:53:23 +04:00
|
|
|
if (!enumerator) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
enumerator->First();
|
|
|
|
nsCOMPtr<nsISupports> currentItem;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = enumerator->CurrentItem(getter_AddRefs(currentItem));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
//XXX: should be while loop?
|
|
|
|
if (currentItem)
|
2000-03-29 16:53:23 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
|
2001-01-28 23:13:07 +03:00
|
|
|
// scan the range for all the independent block content blockSections
|
|
|
|
// and get the block parent of each
|
|
|
|
nsISupportsArray *blockSections;
|
|
|
|
res = NS_NewISupportsArray(&blockSections);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!blockSections) return NS_ERROR_NULL_POINTER;
|
|
|
|
res = GetBlockSectionsForRange(range, blockSections);
|
|
|
|
if (NS_SUCCEEDED(res))
|
2000-03-29 16:53:23 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsIDOMRange *subRange;
|
|
|
|
subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
|
|
|
|
while (subRange)
|
2000-03-29 16:53:23 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMNode>startParent;
|
|
|
|
res = subRange->GetStartContainer(getter_AddRefs(startParent));
|
|
|
|
if (NS_SUCCEEDED(res) && startParent)
|
2000-03-29 16:53:23 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMElement> blockParent;
|
|
|
|
if (aGetLists)
|
|
|
|
{
|
|
|
|
// Get the "ol", "ul", or "dl" parent element
|
|
|
|
res = GetElementOrParentByTagName(NS_ConvertASCIItoUCS2("list"), startParent, getter_AddRefs(blockParent));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
blockParent = do_QueryInterface(GetBlockNodeParent(startParent));
|
|
|
|
}
|
|
|
|
if (NS_SUCCEEDED(res) && blockParent)
|
|
|
|
{
|
|
|
|
nsAutoString blockParentTag;
|
|
|
|
blockParent->GetTagName(blockParentTag);
|
|
|
|
PRBool isRoot;
|
|
|
|
IsRootTag(blockParentTag, isRoot);
|
|
|
|
if ((!isRoot) && (-1==aTagList->IndexOf(blockParentTag))) {
|
|
|
|
aTagList->AppendString(blockParentTag);
|
|
|
|
}
|
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_RELEASE(subRange);
|
|
|
|
if (NS_FAILED(res))
|
|
|
|
break; // don't return here, need to release blockSections
|
|
|
|
blockSections->RemoveElementAt(0);
|
|
|
|
subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
|
2000-03-29 16:53:23 +04:00
|
|
|
}
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_RELEASE(blockSections);
|
2000-03-29 16:53:23 +04:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
return res;
|
1999-09-22 05:21:56 +04:00
|
|
|
}
|
|
|
|
|
2000-06-01 06:38:13 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::GetParagraphState(PRBool *aMixed, nsAWritableString &outFormat)
|
2001-01-28 23:13:07 +03:00
|
|
|
{
|
|
|
|
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
|
2001-04-07 04:45:26 +04:00
|
|
|
if (!aMixed) return NS_ERROR_NULL_POINTER;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIHTMLEditRules> htmlRules = do_QueryInterface(mRules);
|
|
|
|
if (!htmlRules) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
return htmlRules->GetParagraphState(aMixed, outFormat);
|
|
|
|
}
|
2000-06-01 06:38:13 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::GetBackgroundColorState(PRBool *aMixed, nsAWritableString &aOutColor)
|
2001-01-28 23:13:07 +03:00
|
|
|
{
|
|
|
|
//TODO: We don't handle "mixed" correctly!
|
2001-04-07 04:45:26 +04:00
|
|
|
if (!aMixed) return NS_ERROR_NULL_POINTER;
|
|
|
|
*aMixed = PR_FALSE;
|
|
|
|
aOutColor.Assign(NS_LITERAL_STRING(""));
|
2001-01-28 23:13:07 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMElement> element;
|
|
|
|
PRInt32 selectedCount;
|
|
|
|
nsAutoString tagName;
|
|
|
|
nsresult res = GetSelectedOrParentTableElement(*getter_AddRefs(element), tagName, selectedCount);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-06-01 06:38:13 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoString styleName; styleName.AssignWithConversion("bgcolor");
|
2000-06-01 06:38:13 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
while (element)
|
|
|
|
{
|
|
|
|
// We are in a cell or selected table
|
|
|
|
res = element->GetAttribute(styleName, aOutColor);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-06-01 06:38:13 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Done if we have a color explicitly set
|
|
|
|
if (aOutColor.Length() > 0)
|
|
|
|
return NS_OK;
|
2000-06-01 06:38:13 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Once we hit the body, we're done
|
2001-04-06 03:48:01 +04:00
|
|
|
if(nsTextEditUtils::IsBody(element)) return NS_OK;
|
2000-06-01 06:38:13 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// No color is set, but we need to report visible color inherited
|
|
|
|
// from nested cells/tables, so search up parent chain
|
|
|
|
nsCOMPtr<nsIDOMNode> parentNode;
|
|
|
|
res = element->GetParentNode(getter_AddRefs(parentNode));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
element = do_QueryInterface(parentNode);
|
|
|
|
}
|
2000-06-01 06:38:13 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// If no table or cell found, get page body
|
|
|
|
res = nsEditor::GetRootElement(getter_AddRefs(element));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!element) return NS_ERROR_NULL_POINTER;
|
2000-06-01 06:38:13 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
return element->GetAttribute(styleName, aOutColor);
|
|
|
|
}
|
2000-06-01 06:38:13 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::GetListState(PRBool *aMixed, PRBool *aOL, PRBool *aUL, PRBool *aDL)
|
2001-01-28 23:13:07 +03:00
|
|
|
{
|
|
|
|
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
|
2001-04-07 04:45:26 +04:00
|
|
|
if (!aMixed || !aOL || !aUL || !aDL) return NS_ERROR_NULL_POINTER;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIHTMLEditRules> htmlRules = do_QueryInterface(mRules);
|
|
|
|
if (!htmlRules) return NS_ERROR_FAILURE;
|
2000-06-01 06:38:13 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
return htmlRules->GetListState(aMixed, aOL, aUL, aDL);
|
|
|
|
}
|
|
|
|
|
2000-05-04 18:02:03 +04:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::GetListItemState(PRBool *aMixed, PRBool *aLI, PRBool *aDT, PRBool *aDD)
|
2000-05-04 18:02:03 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
|
2001-04-07 04:45:26 +04:00
|
|
|
if (!aMixed || !aLI || !aDT || !aDD) return NS_ERROR_NULL_POINTER;
|
2001-01-28 23:13:07 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsIHTMLEditRules> htmlRules = do_QueryInterface(mRules);
|
|
|
|
if (!htmlRules) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
return htmlRules->GetListItemState(aMixed, aLI, aDT, aDD);
|
2000-05-04 18:02:03 +04:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::GetAlignment(PRBool *aMixed, nsIHTMLEditor::EAlignment *aAlign)
|
2000-04-04 18:51:26 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
|
2001-04-07 04:45:26 +04:00
|
|
|
if (!aMixed || !aAlign) return NS_ERROR_NULL_POINTER;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIHTMLEditRules> htmlRules = do_QueryInterface(mRules);
|
|
|
|
if (!htmlRules) return NS_ERROR_FAILURE;
|
2000-04-04 18:51:26 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
return htmlRules->GetAlignment(aMixed, aAlign);
|
|
|
|
}
|
2000-04-04 18:51:26 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::GetIndentState(PRBool *aCanIndent, PRBool *aCanOutdent)
|
2001-01-28 23:13:07 +03:00
|
|
|
{
|
|
|
|
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
|
2001-04-07 04:45:26 +04:00
|
|
|
if (!aCanIndent || !aCanOutdent) return NS_ERROR_NULL_POINTER;
|
2001-01-28 23:13:07 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsIHTMLEditRules> htmlRules = do_QueryInterface(mRules);
|
|
|
|
if (!htmlRules) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
return htmlRules->GetIndentState(aCanIndent, aCanOutdent);
|
2000-04-04 18:51:26 +04:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::MakeOrChangeList(const nsAReadableString& aListType, PRBool entireList)
|
1999-05-27 01:40:51 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res;
|
1999-08-09 05:37:50 +04:00
|
|
|
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
|
1999-05-27 01:40:51 +04:00
|
|
|
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
1999-10-06 23:34:09 +04:00
|
|
|
PRBool cancel, handled;
|
1999-05-27 01:40:51 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoEditBatch beginBatching(this);
|
|
|
|
nsAutoRules beginRulesSniffing(this, kOpMakeList, nsIEditor::eNext);
|
|
|
|
|
|
|
|
// pre-process
|
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!selection) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsTextRulesInfo ruleInfo(nsTextEditRules::kMakeList);
|
|
|
|
ruleInfo.blockType = &aListType;
|
|
|
|
ruleInfo.entireList = entireList;
|
|
|
|
res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
|
|
|
|
if (cancel || (NS_FAILED(res))) return res;
|
2000-05-31 04:03:02 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!handled)
|
1999-12-15 02:07:12 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
// Find out if the selection is collapsed:
|
|
|
|
PRBool isCollapsed;
|
|
|
|
res = selection->GetIsCollapsed(&isCollapsed);
|
|
|
|
if (NS_FAILED(res)) return res;
|
1999-12-15 02:07:12 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
PRInt32 offset;
|
|
|
|
|
|
|
|
res = GetStartNodeAndOffset(selection, address_of(node), &offset);
|
|
|
|
if (!node) res = NS_ERROR_FAILURE;
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
if (isCollapsed)
|
1999-12-15 02:07:12 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
// have to find a place to put the list
|
|
|
|
nsCOMPtr<nsIDOMNode> parent = node;
|
|
|
|
nsCOMPtr<nsIDOMNode> topChild = node;
|
|
|
|
nsCOMPtr<nsIDOMNode> tmp;
|
|
|
|
|
|
|
|
while ( !CanContainTag(parent, aListType))
|
|
|
|
{
|
|
|
|
parent->GetParentNode(getter_AddRefs(tmp));
|
|
|
|
if (!tmp) return NS_ERROR_FAILURE;
|
|
|
|
topChild = parent;
|
|
|
|
parent = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parent != node)
|
|
|
|
{
|
|
|
|
// we need to split up to the child of parent
|
|
|
|
res = SplitNodeDeep(topChild, node, offset, &offset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
// make a list
|
|
|
|
nsCOMPtr<nsIDOMNode> newList;
|
|
|
|
res = CreateNode(aListType, parent, offset, getter_AddRefs(newList));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// make a list item
|
|
|
|
nsAutoString tag; tag.AssignWithConversion("li");
|
|
|
|
nsCOMPtr<nsIDOMNode> newItem;
|
|
|
|
res = CreateNode(tag, newList, 0, getter_AddRefs(newItem));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = selection->Collapse(newItem,0);
|
|
|
|
if (NS_FAILED(res)) return res;
|
1999-12-15 02:07:12 +03:00
|
|
|
}
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
|
|
|
|
res = mRules->DidDoAction(selection, &ruleInfo, res);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::RemoveList(const nsAReadableString& aListType)
|
2001-01-28 23:13:07 +03:00
|
|
|
{
|
|
|
|
nsresult res;
|
|
|
|
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
|
|
|
|
|
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
|
|
PRBool cancel, handled;
|
1999-12-15 02:07:12 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoEditBatch beginBatching(this);
|
|
|
|
nsAutoRules beginRulesSniffing(this, kOpRemoveList, nsIEditor::eNext);
|
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
// pre-process
|
2001-01-28 23:13:07 +03:00
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(res)) return res;
|
1999-08-19 17:30:48 +04:00
|
|
|
if (!selection) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsTextRulesInfo ruleInfo(nsTextEditRules::kRemoveList);
|
2001-04-18 10:17:05 +04:00
|
|
|
if (!Compare(aListType,NS_LITERAL_STRING("ol"),nsCaseInsensitiveStringComparator()))
|
|
|
|
ruleInfo.bOrdered = PR_TRUE;
|
2001-01-28 23:13:07 +03:00
|
|
|
else ruleInfo.bOrdered = PR_FALSE;
|
|
|
|
res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
|
|
|
|
if (cancel || (NS_FAILED(res))) return res;
|
1999-08-09 05:37:50 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// no default behavior for this yet. what would it mean?
|
|
|
|
|
|
|
|
res = mRules->DidDoAction(selection, &ruleInfo, res);
|
|
|
|
return res;
|
1999-05-27 01:40:51 +04:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::MakeDefinitionItem(const nsAReadableString& aItemType)
|
1999-03-01 22:54:47 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res;
|
1999-03-29 12:02:05 +04:00
|
|
|
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
|
|
|
|
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
1999-10-06 23:34:09 +04:00
|
|
|
PRBool cancel, handled;
|
1999-03-29 12:02:05 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoEditBatch beginBatching(this);
|
|
|
|
nsAutoRules beginRulesSniffing(this, kOpMakeDefListItem, nsIEditor::eNext);
|
|
|
|
|
1999-03-29 12:02:05 +04:00
|
|
|
// pre-process
|
2001-01-28 23:13:07 +03:00
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(res)) return res;
|
1999-08-19 17:30:48 +04:00
|
|
|
if (!selection) return NS_ERROR_NULL_POINTER;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsTextRulesInfo ruleInfo(nsTextEditRules::kMakeDefListItem);
|
|
|
|
ruleInfo.blockType = &aItemType;
|
|
|
|
res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
|
|
|
|
if (cancel || (NS_FAILED(res))) return res;
|
1999-08-09 05:37:50 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!handled)
|
1999-10-06 23:34:09 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
// todo: no default for now. we count on rules to handle it.
|
1999-08-09 05:37:50 +04:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mRules->DidDoAction(selection, &ruleInfo, res);
|
|
|
|
return res;
|
2000-10-12 02:50:14 +04:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::InsertBasicBlock(const nsAReadableString& aBlockType)
|
1999-08-09 05:37:50 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res;
|
|
|
|
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
|
|
PRBool cancel, handled;
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoEditBatch beginBatching(this);
|
|
|
|
nsAutoRules beginRulesSniffing(this, kOpMakeBasicBlock, nsIEditor::eNext);
|
|
|
|
|
|
|
|
// pre-process
|
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!selection) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsTextRulesInfo ruleInfo(nsTextEditRules::kMakeBasicBlock);
|
|
|
|
ruleInfo.blockType = &aBlockType;
|
|
|
|
res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
|
|
|
|
if (cancel || (NS_FAILED(res))) return res;
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!handled)
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
// Find out if the selection is collapsed:
|
|
|
|
PRBool isCollapsed;
|
|
|
|
res = selection->GetIsCollapsed(&isCollapsed);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
PRInt32 offset;
|
|
|
|
|
|
|
|
res = GetStartNodeAndOffset(selection, address_of(node), &offset);
|
|
|
|
if (!node) res = NS_ERROR_FAILURE;
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
if (isCollapsed)
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
// have to find a place to put the block
|
|
|
|
nsCOMPtr<nsIDOMNode> parent = node;
|
|
|
|
nsCOMPtr<nsIDOMNode> topChild = node;
|
|
|
|
nsCOMPtr<nsIDOMNode> tmp;
|
|
|
|
|
|
|
|
while ( !CanContainTag(parent, aBlockType))
|
|
|
|
{
|
|
|
|
parent->GetParentNode(getter_AddRefs(tmp));
|
|
|
|
if (!tmp) return NS_ERROR_FAILURE;
|
|
|
|
topChild = parent;
|
|
|
|
parent = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parent != node)
|
|
|
|
{
|
|
|
|
// we need to split up to the child of parent
|
|
|
|
res = SplitNodeDeep(topChild, node, offset, &offset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
// make a block
|
|
|
|
nsCOMPtr<nsIDOMNode> newBlock;
|
|
|
|
res = CreateNode(aBlockType, parent, offset, getter_AddRefs(newBlock));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// reposition selection to inside the block
|
|
|
|
res = selection->Collapse(newBlock,0);
|
|
|
|
if (NS_FAILED(res)) return res;
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
}
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
|
|
|
|
res = mRules->DidDoAction(selection, &ruleInfo, res);
|
2000-12-07 02:11:21 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::Indent(const nsAReadableString& aIndent)
|
2000-12-07 02:11:21 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res;
|
|
|
|
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
PRBool cancel, handled;
|
|
|
|
PRInt32 theAction = nsTextEditRules::kIndent;
|
|
|
|
PRInt32 opID = kOpIndent;
|
2001-04-18 10:17:05 +04:00
|
|
|
if (!Compare(aIndent,NS_LITERAL_STRING("outdent"),nsCaseInsensitiveStringComparator()))
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
theAction = nsTextEditRules::kOutdent;
|
|
|
|
opID = kOpOutdent;
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoEditBatch beginBatching(this);
|
|
|
|
nsAutoRules beginRulesSniffing(this, opID, nsIEditor::eNext);
|
|
|
|
|
|
|
|
// pre-process
|
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!selection) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsTextRulesInfo ruleInfo(theAction);
|
|
|
|
res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
|
|
|
|
if (cancel || (NS_FAILED(res))) return res;
|
|
|
|
|
|
|
|
if (!handled)
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
// Do default - insert a blockquote node if selection collapsed
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
PRInt32 offset;
|
|
|
|
PRBool isCollapsed;
|
|
|
|
res = selection->GetIsCollapsed(&isCollapsed);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
res = GetStartNodeAndOffset(selection, address_of(node), &offset);
|
|
|
|
if (!node) res = NS_ERROR_FAILURE;
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
nsAutoString inward; inward.AssignWithConversion("indent");
|
|
|
|
if (aIndent == inward)
|
|
|
|
{
|
|
|
|
if (isCollapsed)
|
|
|
|
{
|
|
|
|
// have to find a place to put the blockquote
|
|
|
|
nsCOMPtr<nsIDOMNode> parent = node;
|
|
|
|
nsCOMPtr<nsIDOMNode> topChild = node;
|
|
|
|
nsCOMPtr<nsIDOMNode> tmp;
|
|
|
|
nsAutoString bq(NS_LITERAL_STRING("blockquote"));
|
|
|
|
while ( !CanContainTag(parent, bq))
|
|
|
|
{
|
|
|
|
parent->GetParentNode(getter_AddRefs(tmp));
|
|
|
|
if (!tmp) return NS_ERROR_FAILURE;
|
|
|
|
topChild = parent;
|
|
|
|
parent = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parent != node)
|
|
|
|
{
|
|
|
|
// we need to split up to the child of parent
|
|
|
|
res = SplitNodeDeep(topChild, node, offset, &offset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// make a blockquote
|
|
|
|
nsCOMPtr<nsIDOMNode> newBQ;
|
|
|
|
res = CreateNode(bq, parent, offset, getter_AddRefs(newBQ));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// put a space in it so layout will draw the list item
|
|
|
|
res = selection->Collapse(newBQ,0);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2001-04-07 04:45:26 +04:00
|
|
|
res = InsertText(NS_LITERAL_STRING(" "));
|
2001-01-28 23:13:07 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// reposition selection to before the space character
|
|
|
|
res = GetStartNodeAndOffset(selection, address_of(node), &offset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = selection->Collapse(node,0);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
res = mRules->DidDoAction(selection, &ruleInfo, res);
|
2000-12-07 02:11:21 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
//TODO: IMPLEMENT ALIGNMENT!
|
2000-12-07 02:11:21 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::Align(const nsAReadableString& aAlignType)
|
2000-12-07 02:11:21 +03:00
|
|
|
{
|
|
|
|
nsAutoEditBatch beginBatching(this);
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoRules beginRulesSniffing(this, kOpAlign, nsIEditor::eNext);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
PRBool cancel, handled;
|
2000-12-07 02:11:21 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Find out if the selection is collapsed:
|
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
|
|
nsresult res = GetSelection(getter_AddRefs(selection));
|
2000-12-07 02:11:21 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!selection) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsTextRulesInfo ruleInfo(nsTextEditRules::kAlign);
|
|
|
|
ruleInfo.alignType = &aAlignType;
|
|
|
|
res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
|
|
|
|
if (cancel || NS_FAILED(res))
|
2000-12-07 02:11:21 +03:00
|
|
|
return res;
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mRules->DidDoAction(selection, &ruleInfo, res);
|
|
|
|
return res;
|
|
|
|
}
|
2000-05-06 00:42:36 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
2001-02-27 01:02:58 +03:00
|
|
|
nsHTMLEditor::GetElementOrParentByTagName(const nsAReadableString& aTagName, nsIDOMNode *aNode, nsIDOMElement** aReturn)
|
2001-01-28 23:13:07 +03:00
|
|
|
{
|
|
|
|
if (aTagName.Length() == 0 || !aReturn )
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
nsCOMPtr<nsIDOMNode> currentNode;
|
1999-08-09 05:37:50 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (aNode)
|
|
|
|
currentNode = aNode;
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
else
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
// If no node supplied, get it from anchor node of current selection
|
|
|
|
nsCOMPtr<nsISelection>selection;
|
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
2000-05-06 00:42:36 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!selection) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> anchorNode;
|
|
|
|
res = selection->GetAnchorNode(getter_AddRefs(anchorNode));
|
|
|
|
if(NS_FAILED(res)) return res;
|
|
|
|
if (!anchorNode) return NS_ERROR_FAILURE;
|
1999-11-29 11:28:46 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Try to get the actual selected node
|
|
|
|
PRBool hasChildren = PR_FALSE;
|
|
|
|
anchorNode->HasChildNodes(&hasChildren);
|
|
|
|
if (hasChildren)
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
PRInt32 offset;
|
|
|
|
res = selection->GetAnchorOffset(&offset);
|
|
|
|
if(NS_FAILED(res)) return res;
|
|
|
|
currentNode = nsEditor::GetChildAt(anchorNode, offset);
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
// anchor node is probably a text node - just use that
|
|
|
|
if (!currentNode)
|
|
|
|
currentNode = anchorNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoString TagName(aTagName);
|
|
|
|
TagName.ToLowerCase();
|
|
|
|
PRBool getLink = IsLinkTag(TagName);
|
|
|
|
PRBool getNamedAnchor = IsNamedAnchorTag(TagName);
|
|
|
|
if ( getLink || getNamedAnchor)
|
|
|
|
{
|
|
|
|
TagName.AssignWithConversion("a");
|
|
|
|
}
|
2001-02-27 01:02:58 +03:00
|
|
|
PRBool findTableCell = TagName.EqualsWithConversion("td");
|
|
|
|
PRBool findList = TagName.EqualsWithConversion("list");
|
2000-10-12 02:50:14 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// default is null - no element found
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
PRBool bNodeFound = PR_FALSE;
|
|
|
|
|
|
|
|
while (PR_TRUE)
|
|
|
|
{
|
|
|
|
nsAutoString currentTagName;
|
|
|
|
// Test if we have a link (an anchor with href set)
|
|
|
|
if ( (getLink && nsHTMLEditUtils::IsLink(currentNode)) ||
|
|
|
|
(getNamedAnchor && nsHTMLEditUtils::IsNamedAnchor(currentNode)) )
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
bNodeFound = PR_TRUE;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
if (findList)
|
2000-10-12 02:50:14 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
// Match "ol", "ul", or "dl" for lists
|
|
|
|
if (nsHTMLEditUtils::IsList(currentNode))
|
|
|
|
goto NODE_FOUND;
|
1999-08-09 05:37:50 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
} else if (findTableCell)
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
// Table cells are another special case:
|
|
|
|
// Match either "td" or "th" for them
|
|
|
|
if (nsHTMLEditUtils::IsTableCell(currentNode))
|
|
|
|
goto NODE_FOUND;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
currentNode->GetNodeName(currentTagName);
|
|
|
|
if (currentTagName.EqualsIgnoreCase(TagName))
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
NODE_FOUND:
|
|
|
|
bNodeFound = PR_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
}
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
// Search up the parent chain
|
|
|
|
// We should never fail because of root test below, but lets be safe
|
|
|
|
// XXX: ERROR_HANDLING error return code lost
|
|
|
|
if (!NS_SUCCEEDED(currentNode->GetParentNode(getter_AddRefs(parent))) || !parent)
|
|
|
|
break;
|
1999-08-09 05:37:50 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Stop searching if parent is a body tag
|
|
|
|
nsAutoString parentTagName;
|
|
|
|
parent->GetNodeName(parentTagName);
|
|
|
|
// Note: Originally used IsRoot to stop at table cells,
|
|
|
|
// but that's too messy when you are trying to find the parent table
|
|
|
|
//PRBool isRoot;
|
|
|
|
//if (!NS_SUCCEEDED(IsRootTag(parentTagName, isRoot)) || isRoot)
|
|
|
|
if(parentTagName.EqualsIgnoreCase("body"))
|
|
|
|
break;
|
1999-09-02 21:56:09 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
currentNode = parent;
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
if (bNodeFound)
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMElement> currentElement = do_QueryInterface(currentNode);
|
|
|
|
if (currentElement)
|
1999-11-29 11:28:46 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
*aReturn = currentElement;
|
|
|
|
// Getters must addref
|
|
|
|
NS_ADDREF(*aReturn);
|
1999-11-29 11:28:46 +03:00
|
|
|
}
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
else res = NS_EDITOR_ELEMENT_NOT_FOUND;
|
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2000-08-10 07:43:09 +04:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::GetSelectedElement(const nsAReadableString& aTagName, nsIDOMElement** aReturn)
|
2000-08-10 07:43:09 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!aReturn )
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// default is null - no element found
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
|
|
|
// First look for a single element in selection
|
|
|
|
nsCOMPtr<nsISelection>selection;
|
2000-08-30 06:44:08 +04:00
|
|
|
nsresult res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!selection) return NS_ERROR_NULL_POINTER;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
|
2000-08-30 06:44:08 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
PRBool bNodeFound = PR_FALSE;
|
|
|
|
res=NS_ERROR_NOT_INITIALIZED;
|
|
|
|
PRBool isCollapsed;
|
|
|
|
selection->GetIsCollapsed(&isCollapsed);
|
2000-08-30 06:44:08 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoString domTagName;
|
|
|
|
nsAutoString TagName(aTagName);
|
|
|
|
TagName.ToLowerCase();
|
|
|
|
// Empty string indicates we should match any element tag
|
|
|
|
PRBool anyTag = (TagName.IsEmpty());
|
|
|
|
PRBool isLinkTag = IsLinkTag(TagName);
|
|
|
|
PRBool isNamedAnchorTag = IsNamedAnchorTag(TagName);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMElement> selectedElement;
|
|
|
|
nsCOMPtr<nsIDOMRange> range;
|
|
|
|
res = selection->GetRangeAt(0, getter_AddRefs(range));
|
2000-08-30 06:44:08 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> startParent;
|
|
|
|
PRInt32 startOffset, endOffset;
|
|
|
|
res = range->GetStartContainer(getter_AddRefs(startParent));
|
2000-08-30 06:44:08 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = range->GetStartOffset(&startOffset);
|
2000-08-30 06:44:08 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-08-31 02:49:08 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> endParent;
|
|
|
|
res = range->GetEndContainer(getter_AddRefs(endParent));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = range->GetEndOffset(&endOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-08-31 02:49:08 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Optimization for a single selected element
|
|
|
|
if (startParent && startParent == endParent && (endOffset-startOffset) == 1)
|
2000-08-30 06:44:08 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> selectedNode = GetChildAt(startParent, startOffset);
|
|
|
|
if (NS_FAILED(res)) return NS_OK;
|
|
|
|
if (selectedNode)
|
1999-05-05 08:05:19 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
selectedNode->GetNodeName(domTagName);
|
|
|
|
domTagName.ToLowerCase();
|
|
|
|
|
|
|
|
// Test for appropriate node type requested
|
|
|
|
if (anyTag || (TagName == domTagName) ||
|
|
|
|
(isLinkTag && nsHTMLEditUtils::IsLink(selectedNode)) ||
|
|
|
|
(isNamedAnchorTag && nsHTMLEditUtils::IsNamedAnchor(selectedNode)))
|
|
|
|
{
|
|
|
|
bNodeFound = PR_TRUE;
|
|
|
|
selectedElement = do_QueryInterface(selectedNode);
|
|
|
|
}
|
2000-04-25 18:15:04 +04:00
|
|
|
}
|
|
|
|
}
|
1999-05-05 08:05:19 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!bNodeFound)
|
2000-04-25 18:15:04 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
if (isLinkTag)
|
2000-04-25 18:15:04 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
// Link tag is a special case - we return the anchor node
|
|
|
|
// found for any selection that is totally within a link,
|
|
|
|
// included a collapsed selection (just a caret in a link)
|
|
|
|
nsCOMPtr<nsIDOMNode> anchorNode;
|
|
|
|
res = selection->GetAnchorNode(getter_AddRefs(anchorNode));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
PRInt32 anchorOffset = -1;
|
|
|
|
if (anchorNode)
|
|
|
|
selection->GetAnchorOffset(&anchorOffset);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> focusNode;
|
|
|
|
res = selection->GetFocusNode(getter_AddRefs(focusNode));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
PRInt32 focusOffset = -1;
|
|
|
|
if (focusNode)
|
|
|
|
selection->GetFocusOffset(&focusOffset);
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Link node must be the same for both ends of selection
|
|
|
|
if (NS_SUCCEEDED(res) && anchorNode)
|
2000-04-25 18:15:04 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
#ifdef DEBUG_cmanske
|
|
|
|
{
|
|
|
|
nsAutoString name;
|
|
|
|
anchorNode->GetNodeName(name);
|
|
|
|
printf("GetSelectedElement: Anchor node of selection: ");
|
|
|
|
wprintf(name.GetUnicode());
|
|
|
|
printf(" Offset: %d\n", anchorOffset);
|
|
|
|
focusNode->GetNodeName(name);
|
|
|
|
printf("Focus node of selection: ");
|
|
|
|
wprintf(name.GetUnicode());
|
|
|
|
printf(" Offset: %d\n", focusOffset);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
nsCOMPtr<nsIDOMElement> parentLinkOfAnchor;
|
|
|
|
res = GetElementOrParentByTagName(NS_ConvertASCIItoUCS2("href"), anchorNode, getter_AddRefs(parentLinkOfAnchor));
|
|
|
|
// XXX: ERROR_HANDLING can parentLinkOfAnchor be null?
|
|
|
|
if (NS_SUCCEEDED(res) && parentLinkOfAnchor)
|
|
|
|
{
|
|
|
|
if (isCollapsed)
|
|
|
|
{
|
|
|
|
// We have just a caret in the link
|
|
|
|
bNodeFound = PR_TRUE;
|
|
|
|
} else if(focusNode)
|
|
|
|
{ // Link node must be the same for both ends of selection
|
|
|
|
nsCOMPtr<nsIDOMElement> parentLinkOfFocus;
|
|
|
|
res = GetElementOrParentByTagName(NS_ConvertASCIItoUCS2("href"), focusNode, getter_AddRefs(parentLinkOfFocus));
|
|
|
|
if (NS_SUCCEEDED(res) && parentLinkOfFocus == parentLinkOfAnchor)
|
|
|
|
bNodeFound = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We found a link node parent
|
|
|
|
if (bNodeFound) {
|
|
|
|
// GetElementOrParentByTagName addref'd this, so we don't need to do it here
|
|
|
|
*aReturn = parentLinkOfAnchor;
|
|
|
|
NS_IF_ADDREF(*aReturn);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (anchorOffset >= 0) // Check if link node is the only thing selected
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> anchorChild;
|
|
|
|
anchorChild = GetChildAt(anchorNode,anchorOffset);
|
|
|
|
if (anchorChild && nsHTMLEditUtils::IsLink(anchorChild) &&
|
|
|
|
(anchorNode == focusNode) && focusOffset == (anchorOffset+1))
|
|
|
|
{
|
|
|
|
selectedElement = do_QueryInterface(anchorChild);
|
|
|
|
bNodeFound = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
1999-05-05 08:05:19 +04:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!isCollapsed) // Don't bother to examine selection if it is collapsed
|
2000-05-12 18:57:03 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIEnumerator> enumerator;
|
|
|
|
res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
|
|
|
|
if (NS_SUCCEEDED(res))
|
2000-05-12 18:57:03 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
if(!enumerator)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
enumerator->First();
|
|
|
|
nsCOMPtr<nsISupports> currentItem;
|
|
|
|
res = enumerator->CurrentItem(getter_AddRefs(currentItem));
|
|
|
|
if ((NS_SUCCEEDED(res)) && currentItem)
|
2000-05-12 18:57:03 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMRange> currange( do_QueryInterface(currentItem) );
|
|
|
|
nsCOMPtr<nsIContentIterator> iter;
|
|
|
|
res = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
|
|
|
|
NS_GET_IID(nsIContentIterator),
|
|
|
|
getter_AddRefs(iter));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (iter)
|
2000-05-12 18:57:03 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
iter->Init(currange);
|
|
|
|
// loop through the content iterator for each content node
|
|
|
|
nsCOMPtr<nsIContent> content;
|
|
|
|
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
2000-05-12 18:57:03 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = iter->CurrentNode(getter_AddRefs(content));
|
|
|
|
// Note likely!
|
|
|
|
if (NS_FAILED(res))
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// Query interface to cast nsIContent to nsIDOMNode
|
|
|
|
// then get tagType to compare to aTagName
|
|
|
|
// Clone node of each desired type and append it to the aDomFrag
|
|
|
|
selectedElement = do_QueryInterface(content);
|
|
|
|
if (selectedElement)
|
|
|
|
{
|
|
|
|
// If we already found a node, then we have another element,
|
|
|
|
// thus there's not just one element selected
|
|
|
|
if (bNodeFound)
|
|
|
|
{
|
|
|
|
bNodeFound = PR_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
selectedElement->GetNodeName(domTagName);
|
|
|
|
domTagName.ToLowerCase();
|
|
|
|
|
|
|
|
if (anyTag)
|
|
|
|
{
|
|
|
|
// Get name of first selected element
|
|
|
|
selectedElement->GetTagName(TagName);
|
|
|
|
TagName.ToLowerCase();
|
|
|
|
anyTag = PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The "A" tag is a pain,
|
|
|
|
// used for both link(href is set) and "Named Anchor"
|
|
|
|
nsCOMPtr<nsIDOMNode> selectedNode = do_QueryInterface(selectedElement);
|
|
|
|
if ( (isLinkTag && nsHTMLEditUtils::IsLink(selectedNode)) ||
|
|
|
|
(isNamedAnchorTag && nsHTMLEditUtils::IsNamedAnchor(selectedNode)) )
|
|
|
|
{
|
|
|
|
bNodeFound = PR_TRUE;
|
|
|
|
} else if (TagName == domTagName) { // All other tag names are handled here
|
|
|
|
bNodeFound = PR_TRUE;
|
|
|
|
}
|
|
|
|
if (!bNodeFound)
|
|
|
|
{
|
|
|
|
// Check if node we have is really part of the selection???
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
iter->Next();
|
2000-05-12 18:57:03 +04:00
|
|
|
}
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
} else {
|
|
|
|
// Should never get here?
|
|
|
|
isCollapsed = PR_TRUE;
|
|
|
|
printf("isCollapsed was FALSE, but no elements found in selection\n");
|
2000-05-12 18:57:03 +04:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
} else {
|
|
|
|
printf("Could not create enumerator for GetSelectionProperties\n");
|
2000-05-12 18:57:03 +04:00
|
|
|
}
|
|
|
|
}
|
1999-04-20 21:47:12 +04:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
if (bNodeFound)
|
2000-03-28 04:34:26 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
|
|
|
|
*aReturn = selectedElement;
|
|
|
|
if (selectedElement)
|
|
|
|
{
|
|
|
|
// Getters must addref
|
|
|
|
NS_ADDREF(*aReturn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else res = NS_EDITOR_ELEMENT_NOT_FOUND;
|
2000-03-28 04:34:26 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
return res;
|
1999-04-20 21:47:12 +04:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
2001-02-27 01:02:58 +03:00
|
|
|
nsHTMLEditor::CreateElementWithDefaults(const nsAReadableString& aTagName, nsIDOMElement** aReturn)
|
2000-04-25 18:15:04 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res=NS_ERROR_NOT_INITIALIZED;
|
|
|
|
if (aReturn)
|
|
|
|
*aReturn = nsnull;
|
2000-06-08 18:47:29 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (aTagName.IsEmpty() || !aReturn)
|
2001-02-27 01:02:58 +03:00
|
|
|
// if (!aTagName || !aReturn)
|
2001-01-28 23:13:07 +03:00
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsAutoString TagName(aTagName);
|
|
|
|
TagName.ToLowerCase();
|
|
|
|
nsAutoString realTagName;
|
2000-09-06 03:26:48 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (IsLinkTag(TagName) || IsNamedAnchorTag(TagName))
|
|
|
|
{
|
|
|
|
realTagName.AssignWithConversion("a");
|
|
|
|
} else {
|
|
|
|
realTagName = TagName;
|
|
|
|
}
|
|
|
|
//We don't use editor's CreateElement because we don't want to
|
|
|
|
// go through the transaction system
|
2000-09-06 03:26:48 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMElement>newElement;
|
|
|
|
nsCOMPtr<nsIContent> newContent;
|
|
|
|
nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(mDocWeak);
|
|
|
|
if (!doc) return NS_ERROR_NOT_INITIALIZED;
|
2000-09-06 03:26:48 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
//new call to use instead to get proper HTML element, bug# 39919
|
|
|
|
res = CreateHTMLContent(realTagName, getter_AddRefs(newContent));
|
|
|
|
newElement = do_QueryInterface(newContent);
|
|
|
|
if (NS_FAILED(res) || !newElement)
|
|
|
|
return NS_ERROR_FAILURE;
|
2000-09-06 03:26:48 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Mark the new element dirty, so it will be formatted
|
|
|
|
newElement->SetAttribute(NS_LITERAL_STRING("_moz_dirty"), nsAutoString());
|
2000-09-06 03:26:48 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Set default values for new elements
|
|
|
|
if (TagName.EqualsWithConversion("hr"))
|
|
|
|
{
|
|
|
|
// Note that we read the user's attributes for these from prefs (in InsertHLine JS)
|
|
|
|
newElement->SetAttribute(NS_LITERAL_STRING("align"),NS_LITERAL_STRING("center"));
|
|
|
|
newElement->SetAttribute(NS_LITERAL_STRING("width"),NS_LITERAL_STRING("100%"));
|
|
|
|
newElement->SetAttribute(NS_LITERAL_STRING("size"),NS_LITERAL_STRING("2"));
|
|
|
|
} else if (TagName.EqualsWithConversion("table"))
|
|
|
|
{
|
|
|
|
newElement->SetAttribute(NS_LITERAL_STRING("cellpadding"),NS_LITERAL_STRING("2"));
|
|
|
|
newElement->SetAttribute(NS_LITERAL_STRING("cellspacing"),NS_LITERAL_STRING("2"));
|
|
|
|
newElement->SetAttribute(NS_LITERAL_STRING("border"),NS_LITERAL_STRING("1"));
|
|
|
|
} else if (TagName.EqualsWithConversion("td"))
|
|
|
|
{
|
|
|
|
newElement->SetAttribute(NS_LITERAL_STRING("valign"),NS_LITERAL_STRING("top"));
|
|
|
|
}
|
|
|
|
// ADD OTHER TAGS HERE
|
2000-09-06 03:26:48 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (NS_SUCCEEDED(res))
|
|
|
|
{
|
|
|
|
*aReturn = newElement;
|
|
|
|
// Getters must addref
|
|
|
|
NS_ADDREF(*aReturn);
|
2000-04-25 18:15:04 +04:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
return res;
|
2000-04-25 18:15:04 +04:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::InsertLinkAroundSelection(nsIDOMElement* aAnchorElement)
|
2000-06-08 18:47:29 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res=NS_ERROR_NULL_POINTER;
|
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
|
|
|
|
|
|
if (!aAnchorElement) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
|
|
|
|
// We must have a real selection
|
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (!selection)
|
2000-09-06 03:26:48 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = NS_ERROR_NULL_POINTER;
|
2000-09-06 03:26:48 +04:00
|
|
|
}
|
2000-06-08 18:47:29 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!selection) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
2000-06-08 18:47:29 +04:00
|
|
|
PRBool isCollapsed;
|
|
|
|
res = selection->GetIsCollapsed(&isCollapsed);
|
2001-01-28 23:13:07 +03:00
|
|
|
if (NS_FAILED(res))
|
|
|
|
isCollapsed = PR_TRUE;
|
2000-06-08 18:47:29 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (isCollapsed)
|
2000-06-08 18:47:29 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
printf("InsertLinkAroundSelection called but there is no selection!!!\n");
|
|
|
|
res = NS_OK;
|
|
|
|
} else {
|
|
|
|
// Be sure we were given an anchor element
|
|
|
|
nsCOMPtr<nsIDOMHTMLAnchorElement> anchor = do_QueryInterface(aAnchorElement);
|
|
|
|
if (anchor)
|
2000-06-08 18:47:29 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoString href;
|
|
|
|
res = anchor->GetHref(href);
|
2000-06-08 18:47:29 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
if (href.GetUnicode() && href.Length() > 0)
|
|
|
|
{
|
|
|
|
nsAutoEditBatch beginBatching(this);
|
2001-04-07 04:45:26 +04:00
|
|
|
nsString attribute(NS_LITERAL_STRING("href"));
|
|
|
|
SetInlineProperty(nsIEditProperty::a, attribute, href);
|
2001-01-28 23:13:07 +03:00
|
|
|
//TODO: Enumerate through other properties of the anchor tag
|
|
|
|
// and set those as well.
|
|
|
|
// Optimization: Modify SetTextProperty to set all attributes at once?
|
|
|
|
}
|
2000-06-08 18:47:29 +04:00
|
|
|
}
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
return res;
|
2000-06-08 18:47:29 +04:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::SetBackgroundColor(const nsAReadableString& aColor)
|
2000-06-08 18:47:29 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_PRECONDITION(mDocWeak, "Missing Editor DOM Document");
|
|
|
|
|
|
|
|
// Find a selected or enclosing table element to set background on
|
|
|
|
nsCOMPtr<nsIDOMElement> element;
|
|
|
|
PRInt32 selectedCount;
|
|
|
|
nsAutoString tagName;
|
|
|
|
nsresult res = GetSelectedOrParentTableElement(*getter_AddRefs(element), tagName, selectedCount);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-06-08 18:47:29 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
PRBool setColor = (aColor.Length() > 0);
|
2000-06-08 18:47:29 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (element)
|
2000-06-08 18:47:29 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
if (selectedCount > 0)
|
2000-06-08 18:47:29 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
// Traverse all selected cells
|
|
|
|
nsCOMPtr<nsIDOMElement> cell;
|
|
|
|
res = GetFirstSelectedCell(getter_AddRefs(cell), nsnull);
|
|
|
|
if (NS_SUCCEEDED(res) && cell)
|
|
|
|
{
|
|
|
|
while(cell)
|
|
|
|
{
|
|
|
|
if (setColor)
|
|
|
|
res = SetAttribute(cell, NS_ConvertASCIItoUCS2("bgcolor"), aColor);
|
|
|
|
else
|
|
|
|
res = RemoveAttribute(cell, NS_ConvertASCIItoUCS2("bgcolor"));
|
|
|
|
if (NS_FAILED(res)) break;
|
2000-06-08 18:47:29 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
GetNextSelectedCell(getter_AddRefs(cell), nsnull);
|
|
|
|
};
|
|
|
|
return res;
|
|
|
|
}
|
2000-06-08 18:47:29 +04:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
// If we failed to find a cell, fall through to use originally-found element
|
|
|
|
} else {
|
|
|
|
// No table element -- set the background color on the body tag
|
|
|
|
res = nsEditor::GetRootElement(getter_AddRefs(element));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!element) return NS_ERROR_NULL_POINTER;
|
2000-06-08 18:47:29 +04:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
// Use the editor method that goes through the transaction system
|
|
|
|
if (setColor)
|
|
|
|
res = SetAttribute(element, NS_ConvertASCIItoUCS2("bgcolor"), aColor);
|
|
|
|
else
|
|
|
|
res = RemoveAttribute(element, NS_ConvertASCIItoUCS2("bgcolor"));
|
2000-06-08 18:47:29 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
return res;
|
2000-06-08 18:47:29 +04:00
|
|
|
}
|
|
|
|
|
2001-04-07 04:45:26 +04:00
|
|
|
NS_IMETHODIMP nsHTMLEditor::SetBodyAttribute(const nsAReadableString& aAttribute, const nsAReadableString& aValue)
|
2000-04-25 18:15:04 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res;
|
|
|
|
// TODO: Check selection for Cell, Row, Column or table and do color on appropriate level
|
2000-04-25 18:15:04 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_ASSERTION(mDocWeak, "Missing Editor DOM Document");
|
|
|
|
|
|
|
|
// Set the background color attribute on the body tag
|
|
|
|
nsCOMPtr<nsIDOMElement> bodyElement;
|
|
|
|
|
|
|
|
res = nsEditor::GetRootElement(getter_AddRefs(bodyElement));
|
|
|
|
if (!bodyElement) res = NS_ERROR_NULL_POINTER;
|
|
|
|
if (NS_SUCCEEDED(res))
|
2000-04-25 18:15:04 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
// Use the editor method that goes through the transaction system
|
|
|
|
res = SetAttribute(bodyElement, aAttribute, aValue);
|
2000-04-25 18:15:04 +04:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
return res;
|
2000-04-25 18:15:04 +04:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark nsIEditorStyleSheets methods
|
|
|
|
#pragma mark -
|
|
|
|
#endif
|
2000-04-25 18:15:04 +04:00
|
|
|
|
2000-01-19 00:50:15 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::AddStyleSheet(nsICSSStyleSheet* aSheet)
|
|
|
|
{
|
|
|
|
AddStyleSheetTxn* txn;
|
|
|
|
nsresult rv = CreateTxnForAddStyleSheet(aSheet, &txn);
|
|
|
|
if (!txn) rv = NS_ERROR_NULL_POINTER;
|
|
|
|
if (NS_SUCCEEDED(rv))
|
2000-01-19 00:50:15 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
rv = Do(txn);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
2000-01-19 00:50:15 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
mLastStyleSheet = do_QueryInterface(aSheet); // save it so we can remove before applying the next one
|
2000-01-19 00:50:15 +03:00
|
|
|
}
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
// The transaction system (if any) has taken ownwership of txns
|
|
|
|
NS_IF_RELEASE(txn);
|
2000-01-19 00:50:15 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::RemoveStyleSheet(nsICSSStyleSheet* aSheet)
|
|
|
|
{
|
|
|
|
RemoveStyleSheetTxn* txn;
|
|
|
|
nsresult rv = CreateTxnForRemoveStyleSheet(aSheet, &txn);
|
|
|
|
if (!txn) rv = NS_ERROR_NULL_POINTER;
|
|
|
|
if (NS_SUCCEEDED(rv))
|
2000-01-19 00:50:15 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
rv = Do(txn);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
2000-01-19 00:50:15 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
mLastStyleSheet = nsnull; // forget it
|
2000-01-19 00:50:15 +03:00
|
|
|
}
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
// The transaction system (if any) has taken ownwership of txns
|
|
|
|
NS_IF_RELEASE(txn);
|
2000-01-19 00:50:15 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
return rv;
|
1999-11-11 02:42:11 +03:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Do NOT use transaction system for override style sheets
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::RemoveOverrideStyleSheet(nsICSSStyleSheet* aSheet)
|
1999-11-11 02:42:11 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
|
|
|
if (!ps) return NS_ERROR_NOT_INITIALIZED;
|
1999-11-11 02:42:11 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDocument> document;
|
|
|
|
nsresult rv = ps->GetDocument(getter_AddRefs(document));
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (!document) return NS_ERROR_NULL_POINTER;
|
1999-11-11 02:42:11 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIStyleSet> styleSet;
|
|
|
|
rv = ps->GetStyleSet(getter_AddRefs(styleSet));
|
2000-01-10 13:13:58 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (!styleSet) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsCOMPtr<nsIStyleSheet> styleSheet = do_QueryInterface(aSheet);
|
|
|
|
if (!styleSheet) return NS_ERROR_NULL_POINTER;
|
|
|
|
styleSet->RemoveOverrideStyleSheet(styleSheet);
|
2000-01-10 13:13:58 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// This notifies document observers to rebuild all frames
|
|
|
|
// (this doesn't affect style sheet because it is not a doc sheet)
|
|
|
|
document->SetStyleSheetDisabledState(styleSheet, PR_FALSE);
|
1999-11-11 02:42:11 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
return NS_OK;
|
1999-11-11 02:42:11 +03:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::ApplyOverrideStyleSheet(const nsAReadableString& aURL, nsICSSStyleSheet **aStyleSheet)
|
1999-11-11 02:42:11 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
return ApplyDocumentOrOverrideStyleSheet(aURL, PR_TRUE, aStyleSheet);
|
1999-11-11 02:42:11 +03:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::ApplyStyleSheet(const nsAReadableString& aURL, nsICSSStyleSheet **aStyleSheet)
|
1999-11-11 02:42:11 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
return ApplyDocumentOrOverrideStyleSheet(aURL, PR_FALSE, aStyleSheet);
|
1999-11-11 02:42:11 +03:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
//Note: Loading a document style sheet is undoable, loading an override sheet is not
|
|
|
|
nsresult
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::ApplyDocumentOrOverrideStyleSheet(const nsAReadableString& aURL, PRBool aOverride, nsICSSStyleSheet **aStyleSheet)
|
1999-11-11 02:42:11 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
nsCOMPtr<nsIURI> uaURL;
|
1999-11-11 02:42:11 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
rv = NS_NewURI(getter_AddRefs(uaURL), aURL);
|
1999-11-11 02:42:11 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
nsCOMPtr<nsIDocument> document;
|
2000-08-07 10:05:27 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
|
|
|
if (!ps) return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
rv = ps->GetDocument(getter_AddRefs(document));
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (!document) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIHTMLContentContainer> container = do_QueryInterface(document);
|
|
|
|
if (!container) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsCOMPtr<nsICSSLoader> cssLoader;
|
|
|
|
nsCOMPtr<nsICSSStyleSheet> cssStyleSheet;
|
2000-07-13 03:44:56 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
rv = container->GetCSSLoader(*getter_AddRefs(cssLoader));
|
2000-07-13 03:44:56 +04:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!cssLoader) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
PRBool complete;
|
|
|
|
|
|
|
|
if (aOverride)
|
2000-01-10 13:13:58 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
// We use null for the callback and data pointer because
|
|
|
|
// we MUST ONLY load synchronous local files (no @import)
|
|
|
|
rv = cssLoader->LoadAgentSheet(uaURL, *getter_AddRefs(cssStyleSheet), complete,
|
|
|
|
nsnull);
|
1999-11-13 03:26:45 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Synchronous loads should ALWAYS return completed
|
|
|
|
if (!complete || !cssStyleSheet)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
2000-02-25 07:39:30 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIStyleSheet> styleSheet;
|
|
|
|
styleSheet = do_QueryInterface(cssStyleSheet);
|
|
|
|
nsCOMPtr<nsIStyleSet> styleSet;
|
|
|
|
rv = ps->GetStyleSet(getter_AddRefs(styleSet));
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (!styleSet) return NS_ERROR_NULL_POINTER;
|
1999-11-30 00:15:57 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Add the override style sheet
|
|
|
|
// (This checks if already exists)
|
|
|
|
styleSet->AppendOverrideStyleSheet(styleSheet);
|
|
|
|
// Save doc pointer to be able to use nsIStyleSheet::SetEnabled()
|
|
|
|
styleSheet->SetOwningDocument(document);
|
|
|
|
|
|
|
|
// This notifies document observers to rebuild all frames
|
|
|
|
// (this doesn't affect style sheet because it is not a doc sheet)
|
|
|
|
document->SetStyleSheetDisabledState(styleSheet, PR_FALSE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rv = cssLoader->LoadAgentSheet(uaURL, *getter_AddRefs(cssStyleSheet), complete,
|
|
|
|
this);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (complete)
|
|
|
|
ApplyStyleSheetToPresShellDocument(cssStyleSheet,this);
|
|
|
|
|
|
|
|
//
|
|
|
|
// If not complete, we will be notified later
|
|
|
|
// with a call to ApplyStyleSheetToPresShellDocument().
|
|
|
|
//
|
|
|
|
}
|
|
|
|
if (aStyleSheet)
|
|
|
|
{
|
|
|
|
*aStyleSheet = cssStyleSheet;
|
|
|
|
NS_ADDREF(*aStyleSheet);
|
2000-01-10 13:13:58 +03:00
|
|
|
}
|
2000-07-13 03:44:56 +04:00
|
|
|
}
|
1999-11-24 23:48:59 +03:00
|
|
|
return rv;
|
1999-11-11 02:42:11 +03:00
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark nsIEditorMailSupport methods
|
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
1999-11-24 23:48:59 +03:00
|
|
|
NS_IMETHODIMP
|
2001-01-28 23:13:07 +03:00
|
|
|
nsHTMLEditor::GetEmbeddedObjects(nsISupportsArray** aNodeList)
|
1999-11-11 02:42:11 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!aNodeList)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
1999-11-11 02:42:11 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res;
|
1999-11-11 02:42:11 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
res = NS_NewISupportsArray(aNodeList);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!*aNodeList) return NS_ERROR_NULL_POINTER;
|
1999-11-18 22:43:14 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIContentIterator> iter;
|
|
|
|
res = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
|
|
|
|
NS_GET_IID(nsIContentIterator),
|
|
|
|
getter_AddRefs(iter));
|
|
|
|
if (!iter) return NS_ERROR_NULL_POINTER;
|
|
|
|
if ((NS_SUCCEEDED(res)))
|
|
|
|
{
|
|
|
|
// get the root content
|
|
|
|
nsCOMPtr<nsIContent> rootContent;
|
1999-11-11 02:42:11 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMDocument> domdoc;
|
|
|
|
nsEditor::GetDocument(getter_AddRefs(domdoc));
|
|
|
|
if (!domdoc)
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
2000-01-10 13:13:58 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDocument> doc (do_QueryInterface(domdoc));
|
|
|
|
if (!doc)
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
2000-03-21 02:13:25 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
rootContent = doc->GetRootContent();
|
2000-03-21 02:13:25 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
iter->Init(rootContent);
|
2000-07-13 03:44:56 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// loop through the content iterator for each content node
|
|
|
|
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> content;
|
|
|
|
res = iter->CurrentNode(getter_AddRefs(content));
|
|
|
|
if (NS_FAILED(res))
|
|
|
|
break;
|
|
|
|
nsCOMPtr<nsIDOMNode> node (do_QueryInterface(content));
|
|
|
|
if (node)
|
2000-01-10 13:13:58 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoString tagName;
|
|
|
|
node->GetNodeName(tagName);
|
|
|
|
tagName.ToLowerCase();
|
|
|
|
|
|
|
|
// See if it's an image or an embed
|
|
|
|
if (tagName.EqualsWithConversion("img") || tagName.EqualsWithConversion("embed"))
|
|
|
|
(*aNodeList)->AppendElement(node);
|
|
|
|
else if (tagName.EqualsWithConversion("a"))
|
2000-07-13 03:44:56 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
// XXX Only include links if they're links to file: URLs
|
|
|
|
nsCOMPtr<nsIDOMHTMLAnchorElement> anchor (do_QueryInterface(content));
|
|
|
|
if (anchor)
|
|
|
|
{
|
|
|
|
nsAutoString href;
|
|
|
|
if (NS_SUCCEEDED(anchor->GetHref(href)))
|
|
|
|
if (href.CompareWithConversion("file:", PR_TRUE, 5) == 0)
|
|
|
|
(*aNodeList)->AppendElement(node);
|
|
|
|
}
|
2000-07-13 03:44:56 +04:00
|
|
|
}
|
2000-01-10 13:13:58 +03:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
iter->Next();
|
1999-11-24 23:48:59 +03:00
|
|
|
}
|
2000-07-13 03:44:56 +04:00
|
|
|
}
|
1999-11-30 00:15:57 +03:00
|
|
|
|
1999-11-11 02:42:11 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
|
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark nsIEditor overrides
|
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
2001-02-16 00:51:25 +03:00
|
|
|
// Undo, Redo, Cut, CanCut, Copy, CanCopy, all inherited from nsPlaintextEditor
|
2001-01-28 23:13:07 +03:00
|
|
|
|
2000-09-14 15:45:01 +04:00
|
|
|
static nsresult SetSelectionAroundHeadChildren(nsCOMPtr<nsISelection> aSelection, nsWeakPtr aDocWeak)
|
2000-04-28 09:59:16 +04:00
|
|
|
{
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
// Set selection around <head> node
|
|
|
|
nsCOMPtr<nsIDOMNodeList>nodeList;
|
|
|
|
nsAutoString headTag; headTag.AssignWithConversion("head");
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(aDocWeak);
|
|
|
|
if (!doc) return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
res = doc->GetElementsByTagName(headTag, getter_AddRefs(nodeList));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!nodeList) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
PRUint32 count;
|
|
|
|
nodeList->GetLength(&count);
|
|
|
|
if (count < 1) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> headNode;
|
|
|
|
res = nodeList->Item(0, getter_AddRefs(headNode));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!headNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// Collapse selection to before first child of the head,
|
|
|
|
res = aSelection->Collapse(headNode, 0);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// then extend it to just after
|
|
|
|
nsCOMPtr<nsIDOMNodeList> childNodes;
|
|
|
|
res = headNode->GetChildNodes(getter_AddRefs(childNodes));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!childNodes) return NS_ERROR_NULL_POINTER;
|
|
|
|
PRUint32 childCount;
|
|
|
|
childNodes->GetLength(&childCount);
|
|
|
|
|
|
|
|
return aSelection->Extend(headNode, childCount+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::GetHeadContentsAsHTML(nsAWritableString& aOutputString)
|
2000-04-28 09:59:16 +04:00
|
|
|
{
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
2000-04-28 09:59:16 +04:00
|
|
|
nsresult res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!selection) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// Save current selection
|
|
|
|
nsAutoSelectionReset selectionResetter(selection, this);
|
|
|
|
|
|
|
|
res = SetSelectionAroundHeadChildren(selection, mDocWeak);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2000-08-20 04:34:08 +04:00
|
|
|
res = OutputToString(aOutputString, NS_ConvertASCIItoUCS2("text/html"),
|
2000-04-29 03:39:27 +04:00
|
|
|
nsIDocumentEncoder::OutputSelectionOnly);
|
|
|
|
if (NS_SUCCEEDED(res))
|
|
|
|
{
|
|
|
|
// Selection always includes <body></body>,
|
|
|
|
// so terminate there
|
2001-04-07 04:45:26 +04:00
|
|
|
nsReadingIterator<PRUnichar> findIter,endFindIter;
|
|
|
|
aOutputString.BeginReading(findIter);
|
|
|
|
aOutputString.EndReading(endFindIter);
|
|
|
|
//counting on our parser to always lower case!!!
|
|
|
|
if (FindInReadable(NS_LITERAL_STRING("<body"),findIter,endFindIter))
|
2000-04-29 03:39:27 +04:00
|
|
|
{
|
2001-04-07 04:45:26 +04:00
|
|
|
nsReadingIterator<PRUnichar> beginIter;
|
|
|
|
aOutputString.BeginReading(beginIter);
|
|
|
|
PRInt32 offset = Distance(beginIter, findIter);//get the distance
|
|
|
|
|
|
|
|
nsWritingIterator<PRUnichar> writeIter;
|
|
|
|
aOutputString.BeginWriting(writeIter);
|
2000-04-29 03:39:27 +04:00
|
|
|
// Ensure the string ends in a newline
|
|
|
|
PRUnichar newline ('\n');
|
2001-04-07 04:45:26 +04:00
|
|
|
findIter.advance(-1);
|
|
|
|
if (offset ==0 || (offset >0 && (*findIter) != newline)) //check for 0
|
|
|
|
{
|
|
|
|
writeIter.advance(offset);
|
|
|
|
*writeIter = newline;
|
|
|
|
aOutputString.Truncate(offset+1);
|
|
|
|
}
|
2000-04-29 03:39:27 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
2000-04-28 09:59:16 +04:00
|
|
|
}
|
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::DebugUnitTests(PRInt32 *outNumTests, PRInt32 *outNumTestsFailed)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (!outNumTests || !outNumTestsFailed)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
1999-09-30 00:08:15 +04:00
|
|
|
TextEditorTest *tester = new TextEditorTest();
|
|
|
|
if (!tester)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
tester->Run(this, outNumTests, outNumTestsFailed);
|
|
|
|
delete tester;
|
|
|
|
return NS_OK;
|
|
|
|
#else
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
1999-09-18 03:15:12 +04:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
2000-03-24 03:26:47 +03:00
|
|
|
#pragma mark nsIEditorIMESupport overrides
|
1999-09-18 03:15:12 +04:00
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::SetCompositionString(const nsAReadableString& aCompositionString, nsIPrivateTextRangeList* aTextRangeList,nsTextEventReply* aReply)
|
1999-09-18 03:15:12 +04:00
|
|
|
{
|
1999-10-27 00:04:47 +04:00
|
|
|
NS_ASSERTION(aTextRangeList, "null ptr");
|
|
|
|
if(nsnull == aTextRangeList)
|
2000-01-15 17:29:29 +03:00
|
|
|
return NS_ERROR_NULL_POINTER;
|
1999-09-18 03:15:12 +04:00
|
|
|
nsCOMPtr<nsICaret> caretP;
|
|
|
|
|
2000-02-26 02:50:17 +03:00
|
|
|
// workaround for windows ime bug 23558: we get every ime event twice.
|
|
|
|
// for escape keypress, this causes an empty string to be passed
|
|
|
|
// twice, which freaks out the editor. This is to detect and aviod that
|
|
|
|
// situation:
|
|
|
|
if (aCompositionString.IsEmpty() && !mIMETextNode)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
1999-09-18 03:15:12 +04:00
|
|
|
nsresult result = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(result)) return result;
|
1999-10-26 22:54:47 +04:00
|
|
|
|
1999-10-27 00:04:47 +04:00
|
|
|
mIMETextRangeList = aTextRangeList;
|
1999-10-26 22:54:47 +04:00
|
|
|
nsAutoPlaceHolderBatch batch(this, gIMETxnName);
|
|
|
|
|
2001-04-07 04:45:26 +04:00
|
|
|
result = InsertText(aCompositionString);
|
1999-10-27 00:04:47 +04:00
|
|
|
|
1999-09-18 03:15:12 +04:00
|
|
|
mIMEBufferLength = aCompositionString.Length();
|
|
|
|
|
|
|
|
if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
|
|
|
if (!ps) return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
ps->GetCaret(getter_AddRefs(caretP));
|
2001-02-05 18:44:38 +03:00
|
|
|
caretP->SetCaretDOMSelection(selection);
|
2001-04-20 02:46:29 +04:00
|
|
|
result = caretP->GetCaretCoordinates(nsICaret::eIMECoordinates, selection,
|
2001-02-05 18:44:38 +03:00
|
|
|
&(aReply->mCursorPosition), &(aReply->mCursorIsCollapsed));
|
1999-09-18 03:15:12 +04:00
|
|
|
|
2000-02-26 02:50:17 +03:00
|
|
|
// second part of 23558 fix:
|
|
|
|
if (aCompositionString.IsEmpty())
|
|
|
|
{
|
|
|
|
mIMETextNode = nsnull;
|
|
|
|
}
|
|
|
|
|
1999-09-18 03:15:12 +04:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2000-08-05 01:43:29 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::GetReconversionString(nsReconversionEventReply* aReply)
|
|
|
|
{
|
|
|
|
nsresult res;
|
|
|
|
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
2000-08-05 01:43:29 +04:00
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(res) || !selection)
|
|
|
|
return (res == NS_OK) ? NS_ERROR_FAILURE : res;
|
|
|
|
|
|
|
|
// get the first range in the selection. Since it is
|
|
|
|
// unclear what to do if reconversion happens with a
|
|
|
|
// multirange selection, we will ignore any additional ranges.
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMRange> range;
|
|
|
|
res = selection->GetRangeAt(0, getter_AddRefs(range));
|
|
|
|
if (NS_FAILED(res) || !range)
|
|
|
|
return (res == NS_OK) ? NS_ERROR_FAILURE : res;
|
|
|
|
|
|
|
|
nsAutoString textValue;
|
|
|
|
res = range->ToString(textValue);
|
|
|
|
if (NS_FAILED(res))
|
|
|
|
return res;
|
|
|
|
|
|
|
|
aReply->mReconversionString = (PRUnichar*) nsMemory::Clone(textValue.GetUnicode(),
|
|
|
|
(textValue.Length() + 1) * sizeof(PRUnichar));
|
|
|
|
if (!aReply->mReconversionString)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
// delete the selection
|
|
|
|
res = DeleteSelection(eNone);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
2000-03-24 03:26:47 +03:00
|
|
|
#pragma mark StyleSheet utils
|
1999-08-09 05:37:50 +04:00
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::ReplaceStyleSheet(nsICSSStyleSheet *aNewSheet)
|
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
1999-04-22 18:45:48 +04:00
|
|
|
|
1999-09-30 00:08:15 +04:00
|
|
|
nsAutoEditBatch batchIt(this);
|
1999-08-09 05:37:50 +04:00
|
|
|
|
|
|
|
if (mLastStyleSheet)
|
1999-04-22 18:45:48 +04:00
|
|
|
{
|
1999-08-09 05:37:50 +04:00
|
|
|
rv = RemoveStyleSheet(mLastStyleSheet);
|
1999-08-19 17:30:48 +04:00
|
|
|
//XXX: rv is ignored here, why?
|
1999-08-09 05:37:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
rv = AddStyleSheet(aNewSheet);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
1999-12-04 04:29:18 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::StyleSheetLoaded(nsICSSStyleSheet*aSheet, PRBool aNotify)
|
|
|
|
{
|
|
|
|
ApplyStyleSheetToPresShellDocument(aSheet, this);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-08-09 05:37:50 +04:00
|
|
|
|
|
|
|
/* static callback */
|
|
|
|
void nsHTMLEditor::ApplyStyleSheetToPresShellDocument(nsICSSStyleSheet* aSheet, void *aData)
|
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
|
|
|
nsHTMLEditor *editor = NS_STATIC_CAST(nsHTMLEditor*, aData);
|
|
|
|
if (editor)
|
|
|
|
{
|
|
|
|
rv = editor->ReplaceStyleSheet(aSheet);
|
|
|
|
}
|
1999-08-19 17:30:48 +04:00
|
|
|
// XXX: we lose the return value here. Set a flag in the editor?
|
1999-08-09 05:37:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-12-07 11:30:19 +03:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
2000-03-24 03:26:47 +03:00
|
|
|
#pragma mark nsEditor overrides
|
1999-12-07 11:30:19 +03:00
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/** All editor operations which alter the doc should be prefaced
|
|
|
|
* with a call to StartOperation, naming the action and direction */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
|
|
|
|
{
|
2000-08-14 06:39:37 +04:00
|
|
|
nsEditor::StartOperation(opID, aDirection); // will set mAction, mDirection
|
|
|
|
if (! ((mAction==kOpInsertText) || (mAction==kOpInsertIMEText)) )
|
2000-01-31 13:30:12 +03:00
|
|
|
ClearInlineStylesCache();
|
2000-08-14 06:39:37 +04:00
|
|
|
if (mRules) return mRules->BeforeEdit(mAction, mDirection);
|
1999-12-07 11:30:19 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** All editor operations which alter the doc should be followed
|
2000-08-14 06:39:37 +04:00
|
|
|
* with a call to EndOperation */
|
1999-12-07 11:30:19 +03:00
|
|
|
NS_IMETHODIMP
|
2000-08-14 06:39:37 +04:00
|
|
|
nsHTMLEditor::EndOperation()
|
1999-12-07 11:30:19 +03:00
|
|
|
{
|
2000-08-14 06:39:37 +04:00
|
|
|
// post processing
|
|
|
|
if (! ((mAction==kOpInsertText) || (mAction==kOpInsertIMEText) || (mAction==kOpIgnore)) )
|
2000-01-31 13:30:12 +03:00
|
|
|
ClearInlineStylesCache();
|
2000-08-14 06:39:37 +04:00
|
|
|
nsresult res = NS_OK;
|
|
|
|
if (mRules) res = mRules->AfterEdit(mAction, mDirection);
|
|
|
|
nsEditor::EndOperation(); // will clear mAction, mDirection
|
|
|
|
return res;
|
|
|
|
}
|
1999-12-07 11:30:19 +03:00
|
|
|
|
2000-01-10 13:13:58 +03:00
|
|
|
PRBool
|
2001-04-07 04:45:26 +04:00
|
|
|
nsHTMLEditor::TagCanContainTag(const nsAReadableString& aParentTag, const nsAReadableString& aChildTag)
|
2000-01-10 13:13:58 +03:00
|
|
|
{
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
// COtherDTD gives some unwanted results. We override them here.
|
2001-04-18 10:17:05 +04:00
|
|
|
if (!Compare(aParentTag,NS_LITERAL_STRING("ol"),nsCaseInsensitiveStringComparator()) ||
|
|
|
|
!Compare(aParentTag,NS_LITERAL_STRING("ul"),nsCaseInsensitiveStringComparator()))
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
{
|
|
|
|
// if parent is a list and tag is also a list, say "yes".
|
|
|
|
// This is because the editor does sublists illegally for now.
|
2001-04-18 10:17:05 +04:00
|
|
|
if (!Compare(aChildTag,NS_LITERAL_STRING("ol"),nsCaseInsensitiveStringComparator()) ||
|
|
|
|
!Compare(aChildTag,NS_LITERAL_STRING("ul"),nsCaseInsensitiveStringComparator()))
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2000-06-29 13:23:41 +04:00
|
|
|
|
2001-04-18 10:17:05 +04:00
|
|
|
if (!Compare(aParentTag,NS_LITERAL_STRING("li"),nsCaseInsensitiveStringComparator()))
|
2000-06-29 13:23:41 +04:00
|
|
|
{
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
// list items cant contain list items
|
2001-04-18 10:17:05 +04:00
|
|
|
if (!Compare(aChildTag,NS_LITERAL_STRING("li"),nsCaseInsensitiveStringComparator()))
|
2000-06-29 13:23:41 +04:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
|
|
|
|
/*
|
2000-06-29 13:23:41 +04:00
|
|
|
// if parent is a pre, and child is not inline, say "no"
|
|
|
|
if ( aParentTag.EqualsWithConversion("pre") )
|
|
|
|
{
|
|
|
|
if (aChildTag.EqualsWithConversion("__moz_text"))
|
|
|
|
return PR_TRUE;
|
|
|
|
PRInt32 childTagEnum, parentTagEnum;
|
|
|
|
nsAutoString non_const_childTag(aChildTag);
|
|
|
|
nsAutoString non_const_parentTag(aParentTag);
|
|
|
|
nsresult res = mDTD->StringTagToIntTag(non_const_childTag,&childTagEnum);
|
|
|
|
if (NS_FAILED(res)) return PR_FALSE;
|
|
|
|
res = mDTD->StringTagToIntTag(non_const_parentTag,&parentTagEnum);
|
|
|
|
if (NS_FAILED(res)) return PR_FALSE;
|
|
|
|
if (!mDTD->IsInlineElement(childTagEnum,parentTagEnum))
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 14:57:30 +04:00
|
|
|
*/
|
2000-01-10 13:13:58 +03:00
|
|
|
// else fall thru
|
2000-06-29 13:23:41 +04:00
|
|
|
return nsEditor::TagCanContainTag(aParentTag, aChildTag);
|
2000-01-10 13:13:58 +03:00
|
|
|
}
|
|
|
|
|
1999-12-07 11:30:19 +03:00
|
|
|
|
2000-01-13 13:17:35 +03:00
|
|
|
NS_IMETHODIMP
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditor::SelectEntireDocument(nsISelection *aSelection)
|
2000-01-13 13:17:35 +03:00
|
|
|
{
|
|
|
|
nsresult res;
|
|
|
|
if (!aSelection || !mRules) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
|
|
|
|
// get body node
|
|
|
|
nsCOMPtr<nsIDOMElement>bodyElement;
|
2000-05-04 12:33:48 +04:00
|
|
|
res = GetRootElement(getter_AddRefs(bodyElement));
|
2000-01-13 13:17:35 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
nsCOMPtr<nsIDOMNode>bodyNode = do_QueryInterface(bodyElement);
|
|
|
|
if (!bodyNode) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// is doc empty?
|
|
|
|
PRBool bDocIsEmpty;
|
|
|
|
res = mRules->DocumentIsEmpty(&bDocIsEmpty);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
if (bDocIsEmpty)
|
|
|
|
{
|
|
|
|
// if its empty dont select entire doc - that would select the bogus node
|
|
|
|
return aSelection->Collapse(bodyNode, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return nsEditor::SelectEntireDocument(aSelection);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
2000-03-24 03:26:47 +03:00
|
|
|
#pragma mark Random methods
|
1999-08-09 05:37:50 +04:00
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsHTMLEditor::GetLayoutObject(nsIDOMNode *aNode, nsISupports **aLayoutObject)
|
|
|
|
{
|
|
|
|
nsresult result = NS_ERROR_FAILURE; // we return an error unless we get the index
|
1999-08-25 14:51:55 +04:00
|
|
|
if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
|
|
|
if (!ps) return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
|
|
|
|
if ((nsnull!=aNode))
|
|
|
|
{ // get the content interface
|
|
|
|
nsCOMPtr<nsIContent> nodeAsContent( do_QueryInterface(aNode) );
|
|
|
|
if (nodeAsContent)
|
|
|
|
{ // get the frame from the content interface
|
|
|
|
//Note: frames are not ref counted, so don't use an nsCOMPtr
|
|
|
|
*aLayoutObject = nsnull;
|
|
|
|
result = ps->GetLayoutObjectFor(nodeAsContent, aLayoutObject);
|
1999-08-09 05:37:50 +04:00
|
|
|
}
|
|
|
|
}
|
1999-08-25 14:51:55 +04:00
|
|
|
else {
|
|
|
|
result = NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// this will NOT find aAttribute unless aAttribute has a non-null value
|
|
|
|
// so singleton attributes like <Table border> will not be matched!
|
|
|
|
void nsHTMLEditor::IsTextPropertySetByContent(nsIDOMNode *aNode,
|
|
|
|
nsIAtom *aProperty,
|
2001-04-07 04:45:26 +04:00
|
|
|
const nsAReadableString *aAttribute,
|
|
|
|
const nsAReadableString *aValue,
|
1999-08-09 05:37:50 +04:00
|
|
|
PRBool &aIsSet,
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
nsIDOMNode **aStyleNode,
|
|
|
|
nsString *outValue) const
|
1999-08-09 05:37:50 +04:00
|
|
|
{
|
|
|
|
nsresult result;
|
|
|
|
aIsSet = PR_FALSE; // must be initialized to false for code below to work
|
|
|
|
nsAutoString propName;
|
|
|
|
aProperty->ToString(propName);
|
2000-05-07 05:33:42 +04:00
|
|
|
nsCOMPtr<nsIDOMNode>node = aNode;
|
|
|
|
|
|
|
|
while (node)
|
1999-08-09 05:37:50 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMElement>element;
|
2000-05-07 05:33:42 +04:00
|
|
|
element = do_QueryInterface(node);
|
1999-08-09 05:37:50 +04:00
|
|
|
if (element)
|
|
|
|
{
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
nsAutoString tag, value;
|
1999-08-09 05:37:50 +04:00
|
|
|
element->GetTagName(tag);
|
|
|
|
if (propName.EqualsIgnoreCase(tag))
|
1999-04-22 18:45:48 +04:00
|
|
|
{
|
1999-08-09 05:37:50 +04:00
|
|
|
PRBool found = PR_FALSE;
|
|
|
|
if (aAttribute && 0!=aAttribute->Length())
|
|
|
|
{
|
|
|
|
element->GetAttribute(*aAttribute, value);
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
if (outValue) *outValue = value;
|
2000-05-07 05:33:42 +04:00
|
|
|
if (value.Length())
|
1999-08-09 05:37:50 +04:00
|
|
|
{
|
|
|
|
if (!aValue) {
|
|
|
|
found = PR_TRUE;
|
|
|
|
}
|
2001-04-07 04:45:26 +04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
nsString tString(*aValue);
|
|
|
|
if (tString.EqualsIgnoreCase(value)) {
|
|
|
|
found = PR_TRUE;
|
|
|
|
}
|
|
|
|
else { // we found the prop with the attribute, but the value doesn't match
|
|
|
|
break;
|
|
|
|
}
|
1999-08-09 05:37:50 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
found = PR_TRUE;
|
|
|
|
}
|
2000-03-24 03:26:47 +03:00
|
|
|
if (found)
|
1999-08-09 05:37:50 +04:00
|
|
|
{
|
|
|
|
aIsSet = PR_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
1999-05-05 08:05:19 +04:00
|
|
|
}
|
|
|
|
}
|
1999-08-09 05:37:50 +04:00
|
|
|
nsCOMPtr<nsIDOMNode>temp;
|
2000-05-07 05:33:42 +04:00
|
|
|
result = node->GetParentNode(getter_AddRefs(temp));
|
1999-08-09 05:37:50 +04:00
|
|
|
if (NS_SUCCEEDED(result) && temp) {
|
2000-05-07 05:33:42 +04:00
|
|
|
node = do_QueryInterface(temp);
|
1999-08-09 05:37:50 +04:00
|
|
|
}
|
|
|
|
else {
|
2000-05-07 05:33:42 +04:00
|
|
|
node = do_QueryInterface(nsnull);
|
1999-08-09 05:37:50 +04:00
|
|
|
}
|
1999-05-05 08:05:19 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
void nsHTMLEditor::IsTextStyleSet(nsIStyleContext *aSC,
|
|
|
|
nsIAtom *aProperty,
|
2001-04-07 04:45:26 +04:00
|
|
|
const nsAReadableString *aAttribute,
|
1999-08-09 05:37:50 +04:00
|
|
|
PRBool &aIsSet) const
|
1999-05-05 08:05:19 +04:00
|
|
|
{
|
1999-08-09 05:37:50 +04:00
|
|
|
aIsSet = PR_FALSE;
|
|
|
|
if (aSC && aProperty)
|
1999-05-05 08:05:19 +04:00
|
|
|
{
|
1999-08-09 05:37:50 +04:00
|
|
|
nsStyleFont* font = (nsStyleFont*)aSC->GetStyleData(eStyleStruct_Font);
|
|
|
|
if (nsIEditProperty::i==aProperty)
|
1999-05-05 08:05:19 +04:00
|
|
|
{
|
1999-08-09 05:37:50 +04:00
|
|
|
aIsSet = PRBool(font->mFont.style & NS_FONT_STYLE_ITALIC);
|
|
|
|
}
|
|
|
|
else if (nsIEditProperty::b==aProperty)
|
|
|
|
{ // XXX: check this logic with Peter
|
|
|
|
aIsSet = PRBool(font->mFont.weight > NS_FONT_WEIGHT_NORMAL);
|
1999-05-05 08:05:19 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
|
|
|
#endif
|
1999-08-09 05:37:50 +04:00
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
//================================================================
|
|
|
|
// HTML Editor methods
|
|
|
|
//
|
|
|
|
// Note: Table Editing methods are implemented in nsTableEditor.cpp
|
|
|
|
//
|
1999-08-09 05:37:50 +04:00
|
|
|
|
1999-08-19 17:30:48 +04:00
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
PRBool nsHTMLEditor::IsElementInBody(nsIDOMElement* aElement)
|
|
|
|
{
|
2001-04-06 03:48:01 +04:00
|
|
|
return nsTextEditUtils::InBody(aElement, this);
|
1999-09-14 00:44:38 +04:00
|
|
|
}
|
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
PRBool
|
|
|
|
nsHTMLEditor::SetCaretInTableCell(nsIDOMElement* aElement)
|
1999-08-09 05:37:50 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
PRBool caretIsSet = PR_FALSE;
|
1999-08-09 05:37:50 +04:00
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
if (aElement && IsElementInBody(aElement))
|
1999-05-08 02:26:23 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
nsresult res = NS_OK;
|
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
|
|
|
|
if (content)
|
1999-08-09 05:37:50 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
nsCOMPtr<nsIAtom> atom;
|
|
|
|
content->GetTag(*getter_AddRefs(atom));
|
|
|
|
if (atom.get() == nsIEditProperty::table ||
|
|
|
|
atom.get() == nsIEditProperty::tbody ||
|
|
|
|
atom.get() == nsIEditProperty::thead ||
|
|
|
|
atom.get() == nsIEditProperty::tfoot ||
|
|
|
|
atom.get() == nsIEditProperty::caption ||
|
|
|
|
atom.get() == nsIEditProperty::tr ||
|
|
|
|
atom.get() == nsIEditProperty::td )
|
1999-08-19 17:30:48 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aElement);
|
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
// This MUST succeed if IsElementInBody was TRUE
|
|
|
|
node->GetParentNode(getter_AddRefs(parent));
|
|
|
|
nsCOMPtr<nsIDOMNode>firstChild;
|
|
|
|
// Find deepest child
|
|
|
|
PRBool hasChild;
|
|
|
|
while (NS_SUCCEEDED(node->HasChildNodes(&hasChild)) && hasChild)
|
1999-08-09 05:37:50 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
if (NS_SUCCEEDED(node->GetFirstChild(getter_AddRefs(firstChild))))
|
|
|
|
{
|
|
|
|
parent = node;
|
|
|
|
node = firstChild;
|
1999-05-27 01:40:51 +04:00
|
|
|
}
|
1999-08-09 05:37:50 +04:00
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
// Set selection at beginning of deepest node
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection> selection;
|
2000-03-29 16:53:23 +04:00
|
|
|
res = GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_SUCCEEDED(res) && selection && firstChild)
|
|
|
|
{
|
|
|
|
res = selection->Collapse(firstChild, 0);
|
|
|
|
if (NS_SUCCEEDED(res))
|
|
|
|
caretIsSet = PR_TRUE;
|
|
|
|
}
|
1999-05-27 01:40:51 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
return caretIsSet;
|
|
|
|
}
|
1999-08-19 17:30:48 +04:00
|
|
|
|
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-03-29 16:53:23 +04:00
|
|
|
nsHTMLEditor::IsRootTag(nsString &aTag, PRBool &aIsTag)
|
1999-08-09 05:37:50 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
static char bodyTag[] = "body";
|
|
|
|
static char tdTag[] = "td";
|
|
|
|
static char thTag[] = "th";
|
|
|
|
static char captionTag[] = "caption";
|
|
|
|
if (aTag.EqualsIgnoreCase(bodyTag) ||
|
|
|
|
aTag.EqualsIgnoreCase(tdTag) ||
|
|
|
|
aTag.EqualsIgnoreCase(thTag) ||
|
|
|
|
aTag.EqualsIgnoreCase(captionTag) )
|
1999-08-09 05:37:50 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
aIsTag = PR_TRUE;
|
1999-08-09 05:37:50 +04:00
|
|
|
}
|
|
|
|
else {
|
2000-03-29 16:53:23 +04:00
|
|
|
aIsTag = PR_FALSE;
|
1999-07-14 19:24:33 +04:00
|
|
|
}
|
1999-09-23 08:01:10 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-08-09 05:37:50 +04:00
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::IsSubordinateBlock(nsString &aTag, PRBool &aIsTag)
|
|
|
|
{
|
|
|
|
static char p[] = "p";
|
|
|
|
static char h1[] = "h1";
|
|
|
|
static char h2[] = "h2";
|
|
|
|
static char h3[] = "h3";
|
|
|
|
static char h4[] = "h4";
|
|
|
|
static char h5[] = "h5";
|
|
|
|
static char h6[] = "h6";
|
|
|
|
static char address[] = "address";
|
|
|
|
static char pre[] = "pre";
|
|
|
|
static char li[] = "li";
|
|
|
|
static char dt[] = "dt";
|
|
|
|
static char dd[] = "dd";
|
|
|
|
if (aTag.EqualsIgnoreCase(p) ||
|
|
|
|
aTag.EqualsIgnoreCase(h1) ||
|
|
|
|
aTag.EqualsIgnoreCase(h2) ||
|
|
|
|
aTag.EqualsIgnoreCase(h3) ||
|
|
|
|
aTag.EqualsIgnoreCase(h4) ||
|
|
|
|
aTag.EqualsIgnoreCase(h5) ||
|
|
|
|
aTag.EqualsIgnoreCase(h6) ||
|
|
|
|
aTag.EqualsIgnoreCase(address) ||
|
|
|
|
aTag.EqualsIgnoreCase(pre) ||
|
|
|
|
aTag.EqualsIgnoreCase(li) ||
|
|
|
|
aTag.EqualsIgnoreCase(dt) ||
|
|
|
|
aTag.EqualsIgnoreCase(dd) )
|
|
|
|
{
|
|
|
|
aIsTag = PR_TRUE;
|
1999-08-19 17:30:48 +04:00
|
|
|
}
|
|
|
|
else {
|
2000-03-29 16:53:23 +04:00
|
|
|
aIsTag = PR_FALSE;
|
1999-08-19 17:30:48 +04:00
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-08-19 17:30:48 +04:00
|
|
|
|
1999-05-08 02:26:23 +04:00
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetEnclosingTable: find ancestor who is a table, if any
|
|
|
|
//
|
|
|
|
nsCOMPtr<nsIDOMNode>
|
|
|
|
nsHTMLEditor::GetEnclosingTable(nsIDOMNode *aNode)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aNode, "null node passed to nsHTMLEditor::GetEnclosingTable");
|
|
|
|
nsCOMPtr<nsIDOMNode> tbl, tmp, node = aNode;
|
|
|
|
|
|
|
|
while (!tbl)
|
1999-07-19 23:06:39 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
tmp = GetBlockNodeParent(node);
|
|
|
|
if (!tmp) break;
|
2000-08-14 03:53:34 +04:00
|
|
|
if (nsHTMLEditUtils::IsTable(tmp)) tbl = tmp;
|
2000-03-29 16:53:23 +04:00
|
|
|
node = tmp;
|
1999-07-19 23:06:39 +04:00
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
return tbl;
|
1999-07-19 23:06:39 +04:00
|
|
|
}
|
1999-05-17 16:22:31 +04:00
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void nsHTMLEditor::CacheInlineStyles(nsIDOMNode *aNode)
|
|
|
|
{
|
|
|
|
if (!aNode) return;
|
|
|
|
nsCOMPtr<nsIDOMNode> resultNode;
|
|
|
|
mCachedNode = do_QueryInterface(aNode);
|
|
|
|
IsTextPropertySetByContent(aNode, mBoldAtom, 0, 0, mCachedBoldStyle, getter_AddRefs(resultNode));
|
|
|
|
IsTextPropertySetByContent(aNode, mItalicAtom, 0, 0, mCachedItalicStyle, getter_AddRefs(resultNode));
|
|
|
|
IsTextPropertySetByContent(aNode, mUnderlineAtom, 0, 0, mCachedUnderlineStyle, getter_AddRefs(resultNode));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void nsHTMLEditor::ClearInlineStylesCache()
|
|
|
|
{
|
|
|
|
mCachedNode = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef PRE_NODE_IN_BODY
|
|
|
|
nsCOMPtr<nsIDOMElement> nsHTMLEditor::FindPreElement()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMDocument> domdoc;
|
|
|
|
nsEditor::GetDocument(getter_AddRefs(domdoc));
|
|
|
|
if (!domdoc)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocument> doc (do_QueryInterface(domdoc));
|
|
|
|
if (!doc)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nsIContent* rootContent = doc->GetRootContent();
|
|
|
|
if (!rootContent)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> rootNode (do_QueryInterface(rootContent));
|
|
|
|
if (!rootNode)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nsString prestr ("PRE"); // GetFirstNodeOfType requires capitals
|
|
|
|
nsCOMPtr<nsIDOMNode> preNode;
|
|
|
|
if (!NS_SUCCEEDED(nsEditor::GetFirstNodeOfType(rootNode, prestr,
|
|
|
|
getter_AddRefs(preNode))))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return do_QueryInterface(preNode);
|
|
|
|
}
|
|
|
|
#endif /* PRE_NODE_IN_BODY */
|
|
|
|
|
|
|
|
void nsHTMLEditor::HandleEventListenerError()
|
|
|
|
{
|
2000-10-29 02:17:53 +04:00
|
|
|
if (gNoisy) { printf("failed to add event listener\n"); }
|
2000-03-29 16:53:23 +04:00
|
|
|
// null out the nsCOMPtrs
|
|
|
|
mKeyListenerP = nsnull;
|
|
|
|
mMouseListenerP = nsnull;
|
|
|
|
mTextListenerP = nsnull;
|
|
|
|
mDragListenerP = nsnull;
|
|
|
|
mCompositionListenerP = nsnull;
|
|
|
|
mFocusListenerP = nsnull;
|
|
|
|
}
|
|
|
|
|
1999-08-19 19:15:41 +04:00
|
|
|
/* this method scans the selection for adjacent text nodes
|
|
|
|
* and collapses them into a single text node.
|
|
|
|
* "adjacent" means literally adjacent siblings of the same parent.
|
|
|
|
* Uses nsEditor::JoinNodes so action is undoable.
|
|
|
|
* Should be called within the context of a batch transaction.
|
1999-08-19 17:30:48 +04:00
|
|
|
*/
|
|
|
|
NS_IMETHODIMP
|
2000-03-29 16:53:23 +04:00
|
|
|
nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMRange *aInRange)
|
1999-08-19 17:30:48 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
if (!aInRange) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsAutoTxnsConserveSelection dontSpazMySelection(this);
|
1999-09-30 00:08:15 +04:00
|
|
|
nsVoidArray textNodes; // we can't actually do anything during iteration, so store the text nodes in an array
|
1999-08-19 17:30:48 +04:00
|
|
|
// don't bother ref counting them because we know we can hold them for the
|
|
|
|
// lifetime of this method
|
|
|
|
|
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
// build a list of editable text nodes
|
|
|
|
nsCOMPtr<nsIContentIterator> iter;
|
|
|
|
nsresult result = nsComponentManager::CreateInstance(kSubtreeIteratorCID, nsnull,
|
|
|
|
NS_GET_IID(nsIContentIterator),
|
|
|
|
getter_AddRefs(iter));
|
1999-08-19 17:30:48 +04:00
|
|
|
if (NS_FAILED(result)) return result;
|
2000-03-29 16:53:23 +04:00
|
|
|
if (!iter) return NS_ERROR_NULL_POINTER;
|
1999-08-19 17:30:48 +04:00
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
iter->Init(aInRange);
|
|
|
|
nsCOMPtr<nsIContent> content;
|
2000-04-20 07:59:50 +04:00
|
|
|
result = iter->CurrentNode(getter_AddRefs(content));
|
|
|
|
if (!content) return NS_OK;
|
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
1999-08-19 17:30:48 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
nsCOMPtr<nsIDOMCharacterData> text = do_QueryInterface(content);
|
|
|
|
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(content);
|
|
|
|
if (text && node && IsEditable(node))
|
1999-08-19 17:30:48 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
textNodes.AppendElement((void*)(node.get()));
|
1999-08-19 17:30:48 +04:00
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
iter->Next();
|
|
|
|
iter->CurrentNode(getter_AddRefs(content));
|
1999-08-19 17:30:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// now that I have a list of text nodes, collapse adjacent text nodes
|
2000-03-29 16:53:23 +04:00
|
|
|
// NOTE: assumption that JoinNodes keeps the righthand node
|
|
|
|
nsIDOMNode *leftTextNode = (nsIDOMNode *)(textNodes.ElementAt(0));
|
|
|
|
nsIDOMNode *rightTextNode = (nsIDOMNode *)(textNodes.ElementAt(1));
|
1999-08-19 17:30:48 +04:00
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
while (leftTextNode && rightTextNode)
|
|
|
|
{
|
1999-09-30 00:08:15 +04:00
|
|
|
// get the prev sibling of the right node, and see if it's leftTextNode
|
2000-03-29 16:53:23 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> prevSibOfRightNode;
|
2000-12-09 07:46:08 +03:00
|
|
|
result = GetPriorHTMLSibling(rightTextNode, address_of(prevSibOfRightNode));
|
1999-08-19 17:30:48 +04:00
|
|
|
if (NS_FAILED(result)) return result;
|
2000-03-29 16:53:23 +04:00
|
|
|
if (prevSibOfRightNode && (prevSibOfRightNode.get() == leftTextNode))
|
1999-08-19 17:30:48 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
result = rightTextNode->GetParentNode(getter_AddRefs(parent));
|
|
|
|
if (NS_FAILED(result)) return result;
|
|
|
|
if (!parent) return NS_ERROR_NULL_POINTER;
|
|
|
|
result = JoinNodes(leftTextNode, rightTextNode, parent);
|
1999-08-19 17:30:48 +04:00
|
|
|
if (NS_FAILED(result)) return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
textNodes.RemoveElementAt(0); // remove the leftmost text node from the list
|
2000-03-29 16:53:23 +04:00
|
|
|
leftTextNode = (nsIDOMNode *)(textNodes.ElementAt(0));
|
|
|
|
rightTextNode = (nsIDOMNode *)(textNodes.ElementAt(1));
|
1999-08-19 17:30:48 +04:00
|
|
|
}
|
|
|
|
|
1999-09-30 00:08:15 +04:00
|
|
|
return result;
|
1999-08-19 17:30:48 +04:00
|
|
|
}
|
1999-09-10 22:54:13 +04:00
|
|
|
|
2000-01-26 17:57:43 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditor::GetNextElementByTagName(nsIDOMElement *aCurrentElement,
|
2001-04-07 04:45:26 +04:00
|
|
|
const nsAReadableString *aTagName,
|
2000-01-26 17:57:43 +03:00
|
|
|
nsIDOMElement **aReturn)
|
|
|
|
{
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
if (!aCurrentElement || !aTagName || !aReturn)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsIAtom *tagAtom = NS_NewAtom(*aTagName);
|
|
|
|
if (!tagAtom) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
if (tagAtom==nsIEditProperty::th)
|
|
|
|
tagAtom=nsIEditProperty::td;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> currentNode = do_QueryInterface(aCurrentElement);
|
|
|
|
if (!currentNode)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> nextNode;
|
|
|
|
PRBool done = PR_FALSE;
|
|
|
|
|
|
|
|
do {
|
|
|
|
res = GetNextNode(currentNode, PR_TRUE, getter_AddRefs(nextNode));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!nextNode) break;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAtom> atom = GetTag(currentNode);
|
|
|
|
|
2000-01-26 19:01:49 +03:00
|
|
|
if (tagAtom==atom.get())
|
2000-01-26 17:57:43 +03:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(currentNode);
|
|
|
|
if (!element) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
*aReturn = element;
|
|
|
|
NS_ADDREF(*aReturn);
|
|
|
|
done = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
currentNode = nextNode;
|
|
|
|
} while (!done);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
2000-02-08 04:11:13 +03:00
|
|
|
|
2000-02-10 08:14:52 +03:00
|
|
|
NS_IMETHODIMP
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditor::SetSelectionAtDocumentStart(nsISelection *aSelection)
|
2000-02-10 08:14:52 +03:00
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
nsCOMPtr<nsIDOMElement> bodyElement;
|
2000-05-04 12:33:48 +04:00
|
|
|
nsresult res = GetRootElement(getter_AddRefs(bodyElement));
|
2000-03-24 03:26:47 +03:00
|
|
|
if (NS_SUCCEEDED(res))
|
2000-02-10 08:14:52 +03:00
|
|
|
{
|
|
|
|
if (!bodyElement) return NS_ERROR_NULL_POINTER;
|
|
|
|
res = aSelection->Collapse(bodyElement,0);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2000-02-08 15:53:34 +03:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
|
|
|
#endif
|
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetPriorHTMLSibling: returns the previous editable sibling, if there is
|
|
|
|
// one within the parent
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
|
|
|
|
{
|
|
|
|
if (!outNode || !inNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
*outNode = nsnull;
|
|
|
|
nsCOMPtr<nsIDOMNode> temp, node = do_QueryInterface(inNode);
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
res = node->GetPreviousSibling(getter_AddRefs(temp));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!temp) return NS_OK; // return null sibling
|
|
|
|
// if it's editable, we're done
|
|
|
|
if (IsEditable(temp)) break;
|
|
|
|
// otherwise try again
|
|
|
|
node = temp;
|
|
|
|
}
|
|
|
|
*outNode = temp;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-02-08 15:53:34 +03:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2000-03-24 03:26:47 +03:00
|
|
|
// GetPriorHTMLSibling: returns the previous editable sibling, if there is
|
|
|
|
// one within the parent. just like above routine but
|
|
|
|
// takes a parent/offset instead of a node.
|
|
|
|
//
|
2000-02-08 15:53:34 +03:00
|
|
|
nsresult
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditor::GetPriorHTMLSibling(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
|
2000-02-08 15:53:34 +03:00
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
if (!outNode || !inParent) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
*outNode = nsnull;
|
|
|
|
if (!inOffset) return NS_OK; // return null sibling if at offset zero
|
|
|
|
nsCOMPtr<nsIDOMNode> node = nsEditor::GetChildAt(inParent,inOffset-1);
|
|
|
|
if (IsEditable(node))
|
|
|
|
{
|
|
|
|
*outNode = node;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
// else
|
|
|
|
return GetPriorHTMLSibling(node, outNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetNextHTMLSibling: returns the next editable sibling, if there is
|
|
|
|
// one within the parent
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
|
|
|
|
{
|
|
|
|
if (!outNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
*outNode = nsnull;
|
|
|
|
nsCOMPtr<nsIDOMNode> temp, node = do_QueryInterface(inNode);
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
res = node->GetNextSibling(getter_AddRefs(temp));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!temp) return NS_ERROR_FAILURE;
|
|
|
|
// if it's editable, we're done
|
|
|
|
if (IsEditable(temp)) break;
|
|
|
|
// otherwise try again
|
|
|
|
node = temp;
|
|
|
|
}
|
|
|
|
*outNode = temp;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetNextHTMLSibling: returns the next editable sibling, if there is
|
|
|
|
// one within the parent. just like above routine but
|
|
|
|
// takes a parent/offset instead of a node.
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::GetNextHTMLSibling(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
|
|
|
|
{
|
|
|
|
if (!outNode || !inParent) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
*outNode = nsnull;
|
|
|
|
nsCOMPtr<nsIDOMNode> node = nsEditor::GetChildAt(inParent,inOffset);
|
|
|
|
if (!node) return NS_OK; // return null sibling if no sibling
|
|
|
|
if (IsEditable(node))
|
|
|
|
{
|
|
|
|
*outNode = node;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
// else
|
|
|
|
return GetPriorHTMLSibling(node, outNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetPriorHTMLNode: returns the previous editable leaf node, if there is
|
|
|
|
// one within the <body>
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
|
|
|
|
{
|
|
|
|
if (!outNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult res = GetPriorNode(inNode, PR_TRUE, getter_AddRefs(*outNode));
|
2000-02-08 15:53:34 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
|
|
|
|
// if it's not in the body, then zero it out
|
2001-04-06 03:48:01 +04:00
|
|
|
if (*outNode && !nsTextEditUtils::InBody(*outNode, this))
|
2000-03-24 03:26:47 +03:00
|
|
|
{
|
|
|
|
*outNode = nsnull;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetPriorHTMLNode: same as above but takes {parent,offset} instead of node
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
|
|
|
|
{
|
|
|
|
if (!outNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult res = GetPriorNode(inParent, inOffset, PR_TRUE, getter_AddRefs(*outNode));
|
2000-02-08 15:53:34 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
|
|
|
|
// if it's not in the body, then zero it out
|
2001-04-06 03:48:01 +04:00
|
|
|
if (*outNode && !nsTextEditUtils::InBody(*outNode, this))
|
2000-02-08 15:53:34 +03:00
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
*outNode = nsnull;
|
2000-02-08 15:53:34 +03:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2000-08-26 08:03:50 +04:00
|
|
|
// GetNextHTMLNode: returns the next editable leaf node, if there is
|
2000-03-24 03:26:47 +03:00
|
|
|
// one within the <body>
|
|
|
|
//
|
2000-02-08 15:53:34 +03:00
|
|
|
nsresult
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditor::GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
|
2000-02-08 15:53:34 +03:00
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
if (!outNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult res = GetNextNode(inNode, PR_TRUE, getter_AddRefs(*outNode));
|
2000-02-08 15:53:34 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
// if it's not in the body, then zero it out
|
2001-04-06 03:48:01 +04:00
|
|
|
if (*outNode && !nsTextEditUtils::InBody(*outNode, this))
|
2000-02-08 15:53:34 +03:00
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
*outNode = nsnull;
|
2000-02-08 15:53:34 +03:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2000-03-24 03:26:47 +03:00
|
|
|
// GetNHTMLextNode: same as above but takes {parent,offset} instead of node
|
|
|
|
//
|
2000-02-08 15:53:34 +03:00
|
|
|
nsresult
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditor::GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
|
2000-02-08 15:53:34 +03:00
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
if (!outNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult res = GetNextNode(inParent, inOffset, PR_TRUE, getter_AddRefs(*outNode));
|
2000-02-08 15:53:34 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
// if it's not in the body, then zero it out
|
2001-04-06 03:48:01 +04:00
|
|
|
if (*outNode && !nsTextEditUtils::InBody(*outNode, this))
|
2000-03-24 03:26:47 +03:00
|
|
|
{
|
|
|
|
*outNode = nsnull;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst)
|
|
|
|
{
|
|
|
|
// check parms
|
|
|
|
if (!aOutIsFirst || !aNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// init out parms
|
|
|
|
*aOutIsFirst = PR_FALSE;
|
|
|
|
|
|
|
|
// find first editable child and compare it to aNode
|
|
|
|
nsCOMPtr<nsIDOMNode> parent, firstChild;
|
|
|
|
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
|
2000-02-08 15:53:34 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
if (!parent) return NS_ERROR_FAILURE;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetFirstEditableChild(parent, address_of(firstChild));
|
2000-03-24 03:26:47 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
*aOutIsFirst = (firstChild.get() == aNode);
|
|
|
|
return res;
|
|
|
|
}
|
2000-02-08 15:53:34 +03:00
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast)
|
|
|
|
{
|
|
|
|
// check parms
|
|
|
|
if (!aOutIsLast || !aNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// init out parms
|
|
|
|
*aOutIsLast = PR_FALSE;
|
|
|
|
|
|
|
|
// find last editable child and compare it to aNode
|
|
|
|
nsCOMPtr<nsIDOMNode> parent, lastChild;
|
|
|
|
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
|
2000-02-08 15:53:34 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
if (!parent) return NS_ERROR_FAILURE;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetLastEditableChild(parent, address_of(lastChild));
|
2000-02-08 15:53:34 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
|
|
|
|
*aOutIsLast = (lastChild.get() == aNode);
|
|
|
|
return res;
|
|
|
|
}
|
2000-02-08 15:53:34 +03:00
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild)
|
|
|
|
{
|
|
|
|
// check parms
|
|
|
|
if (!aOutFirstChild || !aNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// init out parms
|
|
|
|
*aOutFirstChild = nsnull;
|
|
|
|
|
|
|
|
// find first editable child
|
|
|
|
nsCOMPtr<nsIDOMNode> child;
|
|
|
|
nsresult res = aNode->GetFirstChild(getter_AddRefs(child));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
while (child && !IsEditable(child))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> tmp;
|
|
|
|
res = child->GetNextSibling(getter_AddRefs(tmp));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!tmp) return NS_ERROR_FAILURE;
|
|
|
|
child = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aOutFirstChild = child;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild)
|
|
|
|
{
|
|
|
|
// check parms
|
|
|
|
if (!aOutLastChild || !aNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// init out parms
|
|
|
|
*aOutLastChild = nsnull;
|
|
|
|
|
|
|
|
// find last editable child
|
|
|
|
nsCOMPtr<nsIDOMNode> child;
|
|
|
|
nsresult res = aNode->GetLastChild(getter_AddRefs(child));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
while (child && !IsEditable(child))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> tmp;
|
|
|
|
res = child->GetPreviousSibling(getter_AddRefs(tmp));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!tmp) return NS_ERROR_FAILURE;
|
|
|
|
child = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aOutLastChild = child;
|
|
|
|
return res;
|
2000-02-08 15:53:34 +03:00
|
|
|
}
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2000-08-26 08:03:50 +04:00
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::GetFirstEditableLeaf( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstLeaf)
|
|
|
|
{
|
|
|
|
// check parms
|
|
|
|
if (!aOutFirstLeaf || !aNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// init out parms
|
|
|
|
*aOutFirstLeaf = nsnull;
|
|
|
|
|
|
|
|
// find leftmost leaf
|
|
|
|
nsCOMPtr<nsIDOMNode> child;
|
|
|
|
nsresult res = GetLeftmostChild(aNode, getter_AddRefs(child));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
while (child && (!IsEditable(child) || !nsHTMLEditUtils::IsLeafNode(child)))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> tmp;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetNextHTMLNode(child, address_of(tmp));
|
2000-08-26 08:03:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!tmp) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// only accept nodes that are descendants of aNode
|
|
|
|
if (nsHTMLEditUtils::IsDescendantOf(tmp, aNode))
|
|
|
|
child = tmp;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
child = nsnull; // this will abort the loop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*aOutFirstLeaf = child;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::GetLastEditableLeaf( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastLeaf)
|
|
|
|
{
|
|
|
|
// check parms
|
|
|
|
if (!aOutLastLeaf || !aNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// init out parms
|
|
|
|
*aOutLastLeaf = nsnull;
|
|
|
|
|
|
|
|
// find leftmost leaf
|
|
|
|
nsCOMPtr<nsIDOMNode> child;
|
|
|
|
nsresult res = GetRightmostChild(aNode, getter_AddRefs(child));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
while (child && (!IsEditable(child) || !nsHTMLEditUtils::IsLeafNode(child)))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> tmp;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetPriorHTMLNode(child, address_of(tmp));
|
2000-08-26 08:03:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!tmp) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// only accept nodes that are descendants of aNode
|
|
|
|
if (nsHTMLEditUtils::IsDescendantOf(tmp, aNode))
|
|
|
|
child = tmp;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
child = nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*aOutLastLeaf = child;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2000-06-22 09:39:54 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// IsEmptyNode: figure out if aNode is an empty node.
|
|
|
|
// A block can have children and still be considered empty,
|
|
|
|
// if the children are empty or non-editable.
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditor::IsEmptyNode( nsIDOMNode *aNode,
|
|
|
|
PRBool *outIsEmptyNode,
|
|
|
|
PRBool aMozBRDoesntCount,
|
2000-07-27 05:03:16 +04:00
|
|
|
PRBool aListOrCellNotEmpty,
|
|
|
|
PRBool aSafeToAskFrames)
|
2000-06-22 09:39:54 +04:00
|
|
|
{
|
|
|
|
if (!aNode || !outIsEmptyNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
*outIsEmptyNode = PR_TRUE;
|
|
|
|
|
|
|
|
// effeciency hack - special case if it's a text node
|
|
|
|
if (nsEditor::IsTextNode(aNode))
|
|
|
|
{
|
|
|
|
PRUint32 length = 0;
|
|
|
|
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
|
|
|
nodeAsText = do_QueryInterface(aNode);
|
|
|
|
nodeAsText->GetLength(&length);
|
|
|
|
if (length) *outIsEmptyNode = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if it's not a text node (handled above) and it's not a container,
|
|
|
|
// then we dont call it empty (it's an <hr>, or <br>, etc).
|
|
|
|
// Also, if it's an anchor then dont treat it as empty - even though
|
|
|
|
// anchors are containers, named anchors are "empty" but we don't
|
|
|
|
// want to treat them as such. Also, don't call ListItems or table
|
|
|
|
// cells empty if caller desires.
|
2001-03-30 18:39:29 +04:00
|
|
|
if (!IsContainer(aNode) || nsHTMLEditUtils::IsAnchor(aNode) ||
|
2000-06-22 09:39:54 +04:00
|
|
|
(aListOrCellNotEmpty && nsHTMLEditUtils::IsListItem(aNode)) ||
|
2000-08-14 04:53:41 +04:00
|
|
|
(aListOrCellNotEmpty && nsHTMLEditUtils::IsTableCell(aNode)) )
|
2000-06-22 09:39:54 +04:00
|
|
|
{
|
|
|
|
*outIsEmptyNode = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-04-17 14:15:05 +04:00
|
|
|
// are we checking a block node?
|
|
|
|
PRBool isBlock = IsBlockNode(aNode);
|
|
|
|
// if so, we allow one br without violating emptiness
|
|
|
|
PRBool seenBR = PR_FALSE;
|
|
|
|
|
|
|
|
// need this for later
|
|
|
|
PRBool isListItemOrCell =
|
|
|
|
nsHTMLEditUtils::IsListItem(aNode) || nsHTMLEditUtils::IsTableCell(aNode);
|
|
|
|
|
2000-06-22 09:39:54 +04:00
|
|
|
// iterate over node. if no children, or all children are either
|
|
|
|
// empty text nodes or non-editable, then node qualifies as empty
|
|
|
|
nsCOMPtr<nsIContentIterator> iter;
|
|
|
|
nsCOMPtr<nsIContent> nodeAsContent = do_QueryInterface(aNode);
|
|
|
|
if (!nodeAsContent) return NS_ERROR_FAILURE;
|
|
|
|
nsresult res = nsComponentManager::CreateInstance(kCContentIteratorCID,
|
|
|
|
nsnull,
|
|
|
|
NS_GET_IID(nsIContentIterator),
|
|
|
|
getter_AddRefs(iter));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = iter->Init(nodeAsContent);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
nsCOMPtr<nsIContent> content;
|
|
|
|
res = iter->CurrentNode(getter_AddRefs(content));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
node = do_QueryInterface(content);
|
|
|
|
if (!node) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// is the node editable and non-empty? if so, return false
|
|
|
|
if (nsEditor::IsEditable(node))
|
|
|
|
{
|
|
|
|
if (nsEditor::IsTextNode(node))
|
|
|
|
{
|
|
|
|
PRUint32 length = 0;
|
|
|
|
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
|
|
|
nodeAsText = do_QueryInterface(node);
|
|
|
|
nodeAsText->GetLength(&length);
|
2000-07-27 05:03:16 +04:00
|
|
|
if (aSafeToAskFrames)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISelectionController> selCon;
|
|
|
|
res = GetSelectionController(getter_AddRefs(selCon));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!selCon) return NS_ERROR_FAILURE;
|
|
|
|
PRBool isVisible = PR_FALSE;
|
2000-07-26 17:07:54 +04:00
|
|
|
// ask the selection controller for information about whether any
|
|
|
|
// of the data in the node is really rendered. This is really
|
|
|
|
// something that frames know about, but we aren't supposed to talk to frames.
|
|
|
|
// So we put a call in the selection controller interface, since it's already
|
2000-07-27 05:03:16 +04:00
|
|
|
// in bed with frames anyway. (this is a fix for bug 22227, and a
|
|
|
|
// partial fix for bug 46209)
|
|
|
|
res = selCon->CheckVisibility(node, 0, length, &isVisible);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (isVisible)
|
|
|
|
{
|
|
|
|
*outIsEmptyNode = PR_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (length)
|
2000-07-26 17:07:54 +04:00
|
|
|
{
|
|
|
|
*outIsEmptyNode = PR_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
2000-06-22 09:39:54 +04:00
|
|
|
}
|
|
|
|
else // an editable, non-text node. we aren't an empty block
|
|
|
|
{
|
|
|
|
// is it the node we are iterating over?
|
|
|
|
if (node.get() == aNode) break;
|
|
|
|
// is it a moz-BR and did the caller ask us not to consider those relevant?
|
2001-04-17 14:15:05 +04:00
|
|
|
if ((aMozBRDoesntCount && nsTextEditUtils::IsMozBR(node)))
|
|
|
|
{
|
|
|
|
// do nothing
|
|
|
|
}
|
|
|
|
else if (isBlock && !seenBR && nsTextEditUtils::IsBreak(node))
|
|
|
|
{
|
|
|
|
// the first br in a block doesn't count
|
|
|
|
seenBR = PR_TRUE;
|
|
|
|
}
|
|
|
|
else
|
2000-06-22 09:39:54 +04:00
|
|
|
{
|
|
|
|
// is it an empty node of some sort?
|
2001-04-17 14:15:05 +04:00
|
|
|
// note: list items or table cells are not considered empty
|
|
|
|
// if they contain other lists or tables
|
|
|
|
if (isListItemOrCell)
|
|
|
|
{
|
|
|
|
if (nsHTMLEditUtils::IsList(node) || nsHTMLEditUtils::IsTable(node))
|
|
|
|
{
|
|
|
|
*outIsEmptyNode = PR_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2000-06-22 09:39:54 +04:00
|
|
|
PRBool isEmptyNode;
|
|
|
|
res = IsEmptyNode(node, &isEmptyNode, aMozBRDoesntCount, aListOrCellNotEmpty);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!isEmptyNode)
|
|
|
|
{
|
|
|
|
// otherwise it ain't empty
|
|
|
|
*outIsEmptyNode = PR_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
res = iter->Next();
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|