1999-03-29 10:21:01 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
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-29 10:21:01 +04: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-29 10:21:01 +04: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-29 10:21:01 +04: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-01-11 23:49:15 +03:00
|
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
1999-03-29 10:21:01 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "nsHTMLEditRules.h"
|
1999-08-09 05:37:50 +04:00
|
|
|
|
1999-03-29 10:21:01 +04:00
|
|
|
#include "nsEditor.h"
|
2000-01-26 03:57:37 +03:00
|
|
|
#include "nsHTMLEditUtils.h"
|
1999-07-20 02:49:21 +04:00
|
|
|
#include "nsHTMLEditor.h"
|
1999-08-09 05:37:50 +04:00
|
|
|
|
1999-04-21 18:49:58 +04:00
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIContentIterator.h"
|
1999-03-29 10:21:01 +04:00
|
|
|
#include "nsIDOMNode.h"
|
1999-04-21 18:49:58 +04:00
|
|
|
#include "nsIDOMText.h"
|
1999-03-29 10:21:01 +04:00
|
|
|
#include "nsIDOMElement.h"
|
|
|
|
#include "nsIDOMNodeList.h"
|
2000-09-14 15:45:01 +04:00
|
|
|
#include "nsISelection.h"
|
|
|
|
#include "nsISelectionPrivate.h"
|
1999-03-29 10:21:01 +04:00
|
|
|
#include "nsIDOMRange.h"
|
2001-01-10 00:44:35 +03:00
|
|
|
#include "nsIDOMNSRange.h"
|
1999-03-29 10:21:01 +04:00
|
|
|
#include "nsIDOMCharacterData.h"
|
|
|
|
#include "nsIEnumerator.h"
|
1999-04-21 18:49:58 +04:00
|
|
|
#include "nsIStyleContext.h"
|
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsLayoutCID.h"
|
2000-08-17 09:26:32 +04:00
|
|
|
#include "nsIPref.h"
|
1999-04-21 18:49:58 +04:00
|
|
|
|
1999-08-09 05:37:50 +04:00
|
|
|
#include "nsEditorUtils.h"
|
1999-03-29 10:21:01 +04:00
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
#include "InsertTextTxn.h"
|
|
|
|
#include "DeleteTextTxn.h"
|
|
|
|
|
1999-05-06 03:27:17 +04:00
|
|
|
//const static char* kMOZEditorBogusNodeAttr="MOZ_EDITOR_BOGUS_NODE";
|
|
|
|
//const static char* kMOZEditorBogusNodeValue="TRUE";
|
2000-01-15 17:29:29 +03:00
|
|
|
const static PRUnichar nbsp = 160;
|
1999-03-29 10:21:01 +04:00
|
|
|
|
1999-08-10 01:50:02 +04:00
|
|
|
static NS_DEFINE_IID(kContentIteratorCID, NS_CONTENTITERATOR_CID);
|
1999-11-25 03:19:45 +03:00
|
|
|
static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
|
2000-08-17 09:26:32 +04:00
|
|
|
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
|
1999-11-25 03:19:45 +03:00
|
|
|
|
1999-06-16 09:02:43 +04:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
kLonely = 0,
|
|
|
|
kPrevSib = 1,
|
|
|
|
kNextSib = 2,
|
|
|
|
kBothSibs = 3
|
|
|
|
};
|
1999-03-29 10:21:01 +04:00
|
|
|
|
2000-08-26 08:03:50 +04:00
|
|
|
/********************************************************
|
|
|
|
* first some helpful funcotrs we will use
|
|
|
|
********************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
class nsTableCellAndListItemFunctor : public nsBoolDomIterFunctor
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual PRBool operator()(nsIDOMNode* aNode) // used to build list of all li's, td's & th's iterator covers
|
|
|
|
{
|
|
|
|
if (nsHTMLEditUtils::IsTableCell(aNode)) return PR_TRUE;
|
|
|
|
if (nsHTMLEditUtils::IsListItem(aNode)) return PR_TRUE;
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class nsBRNodeFunctor : public nsBoolDomIterFunctor
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual PRBool operator()(nsIDOMNode* aNode) // used to build list of all td's & th's iterator covers
|
|
|
|
{
|
|
|
|
if (nsHTMLEditUtils::IsBreak(aNode)) return PR_TRUE;
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class nsEmptyFunctor : public nsBoolDomIterFunctor
|
|
|
|
{
|
|
|
|
public:
|
2001-01-28 23:13:07 +03:00
|
|
|
nsEmptyFunctor(nsHTMLEditor* editor) : mHTMLEditor(editor) {}
|
2000-08-26 08:03:50 +04:00
|
|
|
virtual PRBool operator()(nsIDOMNode* aNode) // used to build list of empty li's and td's
|
|
|
|
{
|
|
|
|
PRBool bIsEmptyNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res = mHTMLEditor->IsEmptyNode(aNode, &bIsEmptyNode, PR_FALSE, PR_FALSE);
|
2000-08-26 08:03:50 +04:00
|
|
|
if (NS_FAILED(res)) return PR_FALSE;
|
|
|
|
if (bIsEmptyNode
|
|
|
|
&& (nsHTMLEditUtils::IsListItem(aNode) || nsHTMLEditUtils::IsTableCellOrCaption(aNode)))
|
|
|
|
{
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
protected:
|
2001-01-28 23:13:07 +03:00
|
|
|
nsHTMLEditor* mHTMLEditor;
|
2000-08-26 08:03:50 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
class nsEditableTextFunctor : public nsBoolDomIterFunctor
|
|
|
|
{
|
|
|
|
public:
|
2001-01-28 23:13:07 +03:00
|
|
|
nsEditableTextFunctor(nsHTMLEditor* editor) : mHTMLEditor(editor) {}
|
2000-08-26 08:03:50 +04:00
|
|
|
virtual PRBool operator()(nsIDOMNode* aNode) // used to build list of empty li's and td's
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
if (nsEditor::IsTextNode(aNode) && mHTMLEditor->IsEditable(aNode))
|
2000-08-26 08:03:50 +04:00
|
|
|
{
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
protected:
|
2001-01-28 23:13:07 +03:00
|
|
|
nsHTMLEditor* mHTMLEditor;
|
2000-08-26 08:03:50 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/********************************************************
|
|
|
|
* routine for making new rules instance
|
|
|
|
********************************************************/
|
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
nsresult
|
|
|
|
NS_NewHTMLEditRules(nsIEditRules** aInstancePtrResult)
|
|
|
|
{
|
|
|
|
nsHTMLEditRules * rules = new nsHTMLEditRules();
|
|
|
|
if (rules)
|
|
|
|
return rules->QueryInterface(NS_GET_IID(nsIEditRules), (void**) aInstancePtrResult);
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
1999-04-05 21:21:59 +04:00
|
|
|
/********************************************************
|
|
|
|
* Constructor/Destructor
|
|
|
|
********************************************************/
|
1999-03-29 10:21:01 +04:00
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditRules::nsHTMLEditRules() :
|
|
|
|
mDocChangeRange(nsnull)
|
|
|
|
,mListenerEnabled(PR_TRUE)
|
2000-08-17 09:26:32 +04:00
|
|
|
,mReturnInEmptyLIKillsList(PR_TRUE)
|
2000-03-24 03:26:47 +03:00
|
|
|
,mUtilRange(nsnull)
|
|
|
|
,mJoinOffset(0)
|
1999-03-29 10:21:01 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsHTMLEditRules::~nsHTMLEditRules()
|
|
|
|
{
|
1999-11-25 03:19:45 +03:00
|
|
|
// remove ourselves as a listener to edit actions
|
2000-03-24 03:26:47 +03:00
|
|
|
// In the normal case, we have already been removed by
|
|
|
|
// ~nsHTMLEditor, in which case we will get an error here
|
|
|
|
// which we ignore. But this allows us to add the ability to
|
|
|
|
// switch rule sets on the fly if we want.
|
2001-01-28 23:13:07 +03:00
|
|
|
mHTMLEditor->RemoveEditActionListener(this);
|
1999-03-29 10:21:01 +04:00
|
|
|
}
|
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
/********************************************************
|
|
|
|
* XPCOM Cruft
|
|
|
|
********************************************************/
|
|
|
|
|
|
|
|
NS_IMPL_ADDREF_INHERITED(nsHTMLEditRules, nsTextEditRules)
|
|
|
|
NS_IMPL_RELEASE_INHERITED(nsHTMLEditRules, nsTextEditRules)
|
2000-05-03 04:14:28 +04:00
|
|
|
NS_IMPL_QUERY_INTERFACE3(nsHTMLEditRules, nsIHTMLEditRules, nsIEditRules, nsIEditActionListener)
|
2000-03-24 03:26:47 +03:00
|
|
|
|
1999-04-05 21:21:59 +04:00
|
|
|
|
|
|
|
/********************************************************
|
|
|
|
* Public methods
|
|
|
|
********************************************************/
|
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
NS_IMETHODIMP
|
2001-01-28 23:13:07 +03:00
|
|
|
nsHTMLEditRules::Init(nsPlaintextEditor *aEditor, PRUint32 aFlags)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
mHTMLEditor = NS_STATIC_CAST(nsHTMLEditor*, aEditor);
|
|
|
|
nsresult res;
|
|
|
|
|
|
|
|
// call through to base class Init
|
|
|
|
res = nsTextEditRules::Init(aEditor, aFlags);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2000-08-17 09:26:32 +04:00
|
|
|
// cache any prefs we care about
|
|
|
|
NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &res);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
char *returnInEmptyLIKillsList = 0;
|
2000-08-17 13:51:27 +04:00
|
|
|
res = prefs->CopyCharPref("editor.html.typing.returnInEmptyListItemClosesList",
|
|
|
|
&returnInEmptyLIKillsList);
|
2000-08-17 09:26:32 +04:00
|
|
|
|
|
|
|
if (NS_SUCCEEDED(res) && returnInEmptyLIKillsList)
|
|
|
|
{
|
2000-08-17 13:51:27 +04:00
|
|
|
if (!strncmp(returnInEmptyLIKillsList, "false", 5))
|
2000-08-17 09:26:32 +04:00
|
|
|
mReturnInEmptyLIKillsList = PR_FALSE;
|
|
|
|
else
|
|
|
|
mReturnInEmptyLIKillsList = PR_TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mReturnInEmptyLIKillsList = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
// make a utility range for use by the listenter
|
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
|
|
|
mUtilRange = do_CreateInstance(kRangeCID);
|
|
|
|
if (!mUtilRange) return NS_ERROR_NULL_POINTER;
|
2001-01-28 23:13:07 +03:00
|
|
|
|
1999-11-29 11:28:46 +03:00
|
|
|
// set up mDocChangeRange to be whole doc
|
|
|
|
nsCOMPtr<nsIDOMElement> bodyElem;
|
|
|
|
nsCOMPtr<nsIDOMNode> bodyNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
mHTMLEditor->GetRootElement(getter_AddRefs(bodyElem));
|
1999-11-29 11:28:46 +03:00
|
|
|
bodyNode = do_QueryInterface(bodyElem);
|
|
|
|
if (bodyNode)
|
|
|
|
{
|
2000-01-13 13:17:35 +03:00
|
|
|
// temporarily turn off rules sniffing
|
|
|
|
nsAutoLockRulesSniffing lockIt((nsTextEditRules*)this);
|
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 (!mDocChangeRange)
|
|
|
|
{
|
|
|
|
mDocChangeRange = do_CreateInstance(kRangeCID);
|
|
|
|
if (!mDocChangeRange) return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
1999-11-29 11:28:46 +03:00
|
|
|
mDocChangeRange->SelectNode(bodyNode);
|
2000-08-19 09:58:11 +04:00
|
|
|
res = AdjustSpecialBreaks();
|
2000-01-13 13:17:35 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-11-29 11:28:46 +03:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
// add ourselves as a listener to edit actions
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->AddEditActionListener(this);
|
1999-11-25 03:19:45 +03:00
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
1999-12-07 11:30:19 +03:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditRules::BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
|
|
|
{
|
|
|
|
if (mLockRulesSniffing) return NS_OK;
|
|
|
|
|
|
|
|
nsAutoLockRulesSniffing lockIt((nsTextEditRules*)this);
|
|
|
|
|
|
|
|
if (!mActionNesting)
|
|
|
|
{
|
2001-01-10 00:44:35 +03:00
|
|
|
nsCOMPtr<nsIDOMNSRange> nsrange;
|
|
|
|
if(mDocChangeRange)
|
|
|
|
{
|
|
|
|
nsrange = do_QueryInterface(mDocChangeRange);
|
2001-02-06 05:55:06 +03:00
|
|
|
if (!nsrange)
|
2001-01-10 00:44:35 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsrange->NSDetach(); // clear out our accounting of what changed
|
|
|
|
}
|
|
|
|
if(mUtilRange)
|
|
|
|
{
|
|
|
|
nsrange = do_QueryInterface(mUtilRange);
|
2001-02-06 05:55:06 +03:00
|
|
|
if (!nsrange)
|
2001-01-10 00:44:35 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsrange->NSDetach(); // ditto for mUtilRange.
|
|
|
|
}
|
2000-01-10 13:13:58 +03:00
|
|
|
// turn off caret
|
2000-04-27 11:37:12 +04:00
|
|
|
nsCOMPtr<nsISelectionController> selCon;
|
2001-01-28 23:13:07 +03:00
|
|
|
mHTMLEditor->GetSelectionController(getter_AddRefs(selCon));
|
2000-04-27 11:37:12 +04:00
|
|
|
if (selCon) selCon->SetCaretEnabled(PR_FALSE);
|
2000-01-10 13:13:58 +03:00
|
|
|
// check that selection is in subtree defined by body node
|
|
|
|
ConfirmSelectionInBody();
|
2000-02-25 07:39:30 +03:00
|
|
|
// let rules remember the top level action
|
|
|
|
mTheAction = action;
|
1999-12-07 11:30:19 +03:00
|
|
|
}
|
|
|
|
mActionNesting++;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
1999-12-07 11:30:19 +03:00
|
|
|
{
|
|
|
|
if (mLockRulesSniffing) return NS_OK;
|
|
|
|
|
|
|
|
nsAutoLockRulesSniffing lockIt(this);
|
|
|
|
|
|
|
|
NS_PRECONDITION(mActionNesting>0, "bad action nesting!");
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
if (!--mActionNesting)
|
|
|
|
{
|
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
|
|
|
// do all the tricky stuff
|
|
|
|
res = AfterEditInner(action, aDirection);
|
|
|
|
// turn on caret
|
|
|
|
nsCOMPtr<nsISelectionController> selCon;
|
2001-01-28 23:13:07 +03:00
|
|
|
mHTMLEditor->GetSelectionController(getter_AddRefs(selCon));
|
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 (selCon) selCon->SetCaretEnabled(PR_TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::AfterEditInner(PRInt32 action, nsIEditor::EDirection aDirection)
|
|
|
|
{
|
|
|
|
ConfirmSelectionInBody();
|
|
|
|
if (action == nsEditor::kOpIgnore) return NS_OK;
|
|
|
|
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection>selection;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
|
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;
|
|
|
|
|
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
|
|
|
// do we have a real range to act on?
|
|
|
|
PRBool bDamagedRange = PR_FALSE;
|
|
|
|
if (mDocChangeRange)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> rangeStartParent, rangeEndParent;
|
|
|
|
mDocChangeRange->GetStartContainer(getter_AddRefs(rangeStartParent));
|
|
|
|
mDocChangeRange->GetEndContainer(getter_AddRefs(rangeEndParent));
|
|
|
|
if (rangeStartParent && rangeEndParent)
|
|
|
|
bDamagedRange = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bDamagedRange && !((action == nsEditor::kOpUndo) || (action == nsEditor::kOpRedo)))
|
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
|
|
|
{
|
|
|
|
// dont let any txns in here move the selection around behind our back.
|
|
|
|
// Note that this won't prevent explicit selection setting from working.
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
|
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
|
|
|
|
|
|
|
// expand the "changed doc range" as needed
|
|
|
|
res = PromoteRange(mDocChangeRange, action);
|
|
|
|
if (NS_FAILED(res)) return res;
|
1999-12-07 11:30:19 +03:00
|
|
|
|
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
|
|
|
// add in any needed <br>s, and remove any unneeded ones.
|
|
|
|
res = AdjustSpecialBreaks();
|
1999-12-07 11:30:19 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
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
|
|
|
// merge any adjacent text nodes
|
|
|
|
if ( (action != nsEditor::kOpInsertText &&
|
|
|
|
action != nsEditor::kOpInsertIMEText) )
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CollapseAdjacentTextNodes(mDocChangeRange);
|
2000-03-24 03:26:47 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
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
|
|
|
}
|
|
|
|
|
|
|
|
// adjust whitespace for insert text and delete actions
|
|
|
|
if ((action == nsEditor::kOpInsertText) ||
|
|
|
|
(action == nsEditor::kOpInsertIMEText) ||
|
|
|
|
(action == nsEditor::kOpDeleteSelection))
|
|
|
|
{
|
|
|
|
res = AdjustWhitespace(selection);
|
1999-12-07 11:30:19 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
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
|
|
|
}
|
|
|
|
|
|
|
|
// replace newlines that are preformatted
|
|
|
|
// MOOSE: This is buttUgly. A better way to
|
|
|
|
// organize the action enum is in order.
|
|
|
|
if ((action == nsEditor::kOpInsertText) ||
|
|
|
|
(action == nsEditor::kOpInsertIMEText) ||
|
|
|
|
(action == nsHTMLEditor::kOpInsertElement) ||
|
|
|
|
(action == nsHTMLEditor::kOpInsertQuotation) ||
|
|
|
|
(action == nsEditor::kOpInsertNode))
|
|
|
|
{
|
|
|
|
res = ReplaceNewlines(mDocChangeRange);
|
|
|
|
}
|
|
|
|
|
|
|
|
// clean up any empty nodes in the selection
|
|
|
|
res = RemoveEmptyNodes();
|
|
|
|
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
|
|
|
// adjust selection for insert text, html paste, and delete actions
|
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 ((action == nsEditor::kOpInsertText) ||
|
|
|
|
(action == nsEditor::kOpInsertIMEText) ||
|
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
|
|
|
(action == nsEditor::kOpDeleteSelection) ||
|
2001-02-01 02:58:42 +03:00
|
|
|
(action == nsEditor::kOpInsertBreak) ||
|
2001-01-28 23:13:07 +03:00
|
|
|
(action == nsHTMLEditor::kOpHTMLPaste))
|
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
|
|
|
{
|
|
|
|
res = AdjustSelection(selection, aDirection);
|
1999-12-07 11:30:19 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
2000-01-10 13:13:58 +03:00
|
|
|
|
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
|
|
|
// detect empty doc
|
|
|
|
res = CreateBogusNodeIfNeeded(selection);
|
1999-12-07 11:30:19 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-04-05 21:21:59 +04:00
|
|
|
NS_IMETHODIMP
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::WillDoAction(nsISelection *aSelection,
|
1999-10-06 23:34:09 +04:00
|
|
|
nsRulesInfo *aInfo,
|
|
|
|
PRBool *aCancel,
|
|
|
|
PRBool *aHandled)
|
1999-04-05 21:21:59 +04:00
|
|
|
{
|
1999-10-06 23:34:09 +04:00
|
|
|
if (!aInfo || !aCancel || !aHandled)
|
1999-04-05 21:21:59 +04:00
|
|
|
return NS_ERROR_NULL_POINTER;
|
2000-10-29 02:17:53 +04:00
|
|
|
#if defined(DEBUG_ftang)
|
|
|
|
printf("nsHTMLEditRules::WillDoAction action = %d\n", aInfo->action);
|
|
|
|
#endif
|
1999-06-08 10:04:51 +04:00
|
|
|
|
|
|
|
*aCancel = PR_FALSE;
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_FALSE;
|
1999-04-05 21:21:59 +04:00
|
|
|
|
1999-04-12 16:01:32 +04:00
|
|
|
// my kingdom for dynamic cast
|
|
|
|
nsTextRulesInfo *info = NS_STATIC_CAST(nsTextRulesInfo*, aInfo);
|
|
|
|
|
|
|
|
switch (info->action)
|
1999-04-05 21:21:59 +04:00
|
|
|
{
|
1999-04-12 16:01:32 +04:00
|
|
|
case kInsertText:
|
1999-11-01 18:15:35 +03:00
|
|
|
case kInsertTextIME:
|
|
|
|
return WillInsertText(info->action,
|
|
|
|
aSelection,
|
1999-04-12 16:01:32 +04:00
|
|
|
aCancel,
|
1999-10-06 23:34:09 +04:00
|
|
|
aHandled,
|
1999-04-12 16:01:32 +04:00
|
|
|
info->inString,
|
|
|
|
info->outString,
|
1999-06-08 10:04:51 +04:00
|
|
|
info->maxLength);
|
1999-04-05 21:21:59 +04:00
|
|
|
case kInsertBreak:
|
1999-10-06 23:34:09 +04:00
|
|
|
return WillInsertBreak(aSelection, aCancel, aHandled);
|
1999-04-26 18:08:52 +04:00
|
|
|
case kDeleteSelection:
|
1999-10-06 23:34:09 +04:00
|
|
|
return WillDeleteSelection(aSelection, info->collapsedAction, aCancel, aHandled);
|
1999-06-03 10:01:08 +04:00
|
|
|
case kMakeList:
|
2000-09-14 09:59:19 +04:00
|
|
|
return WillMakeList(aSelection, info->blockType, info->entireList, aCancel, aHandled);
|
1999-06-03 10:01:08 +04:00
|
|
|
case kIndent:
|
1999-10-06 23:34:09 +04:00
|
|
|
return WillIndent(aSelection, aCancel, aHandled);
|
1999-06-03 10:01:08 +04:00
|
|
|
case kOutdent:
|
1999-10-06 23:34:09 +04:00
|
|
|
return WillOutdent(aSelection, aCancel, aHandled);
|
1999-06-03 10:01:08 +04:00
|
|
|
case kAlign:
|
1999-10-06 23:34:09 +04:00
|
|
|
return WillAlign(aSelection, info->alignType, aCancel, aHandled);
|
1999-08-18 12:13:06 +04:00
|
|
|
case kMakeBasicBlock:
|
1999-10-06 23:34:09 +04:00
|
|
|
return WillMakeBasicBlock(aSelection, info->blockType, aCancel, aHandled);
|
1999-09-06 23:51:59 +04:00
|
|
|
case kRemoveList:
|
1999-10-06 23:34:09 +04:00
|
|
|
return WillRemoveList(aSelection, info->bOrdered, aCancel, aHandled);
|
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
|
|
|
case kMakeDefListItem:
|
2000-09-14 09:59:19 +04:00
|
|
|
return WillMakeDefListItem(aSelection, info->blockType, info->entireList, aCancel, aHandled);
|
1999-08-10 02:51:40 +04:00
|
|
|
case kInsertElement:
|
|
|
|
return WillInsert(aSelection, aCancel);
|
1999-04-05 21:21:59 +04:00
|
|
|
}
|
1999-10-06 23:34:09 +04:00
|
|
|
return nsTextEditRules::WillDoAction(aSelection, aInfo, aCancel, aHandled);
|
1999-04-05 21:21:59 +04:00
|
|
|
}
|
|
|
|
|
1999-05-27 02:44:08 +04:00
|
|
|
|
1999-04-05 21:21:59 +04:00
|
|
|
NS_IMETHODIMP
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::DidDoAction(nsISelection *aSelection,
|
1999-04-12 16:01:32 +04:00
|
|
|
nsRulesInfo *aInfo, nsresult aResult)
|
1999-04-05 21:21:59 +04:00
|
|
|
{
|
2000-03-31 02:57:19 +04:00
|
|
|
nsTextRulesInfo *info = NS_STATIC_CAST(nsTextRulesInfo*, aInfo);
|
|
|
|
switch (info->action)
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
case kInsertBreak:
|
|
|
|
return DidInsertBreak(aSelection, aResult);
|
2000-03-31 02:57:19 +04:00
|
|
|
case kMakeBasicBlock:
|
2000-08-26 08:03:50 +04:00
|
|
|
case kIndent:
|
|
|
|
case kOutdent:
|
|
|
|
case kAlign:
|
2000-03-31 02:57:19 +04:00
|
|
|
return DidMakeBasicBlock(aSelection, aInfo, aResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
// default: pass thru to nsTextEditRules
|
|
|
|
return nsTextEditRules::DidDoAction(aSelection, aInfo, aResult);
|
1999-04-05 21:21:59 +04:00
|
|
|
}
|
|
|
|
|
2000-05-03 04:14:28 +04:00
|
|
|
/********************************************************
|
|
|
|
* nsIHTMLEditRules methods
|
|
|
|
********************************************************/
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-06-02 11:47:53 +04:00
|
|
|
nsHTMLEditRules::GetListState(PRBool &aMixed, PRBool &aOL, PRBool &aUL, PRBool &aDL)
|
2000-05-03 04:14:28 +04:00
|
|
|
{
|
|
|
|
aMixed = PR_FALSE;
|
|
|
|
aOL = PR_FALSE;
|
|
|
|
aUL = PR_FALSE;
|
2000-06-02 11:47:53 +04:00
|
|
|
aDL = PR_FALSE;
|
2000-05-03 04:14:28 +04:00
|
|
|
PRBool bNonList = PR_FALSE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
2000-12-09 07:46:08 +03:00
|
|
|
nsresult res = GetListActionNodes(address_of(arrayOfNodes), PR_FALSE, PR_TRUE);
|
2000-05-03 04:14:28 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
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
|
|
|
// examine list type for nodes in selection
|
2000-05-03 04:14:28 +04:00
|
|
|
PRUint32 listCount;
|
|
|
|
PRInt32 i;
|
|
|
|
arrayOfNodes->Count(&listCount);
|
|
|
|
for (i=(PRInt32)listCount-1; i>=0; i--)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
|
|
|
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->NodeIsType(curNode,nsIEditProperty::ul))
|
2000-05-03 04:14:28 +04:00
|
|
|
aUL = PR_TRUE;
|
2001-01-28 23:13:07 +03:00
|
|
|
else if (mHTMLEditor->NodeIsType(curNode,nsIEditProperty::ol))
|
2000-05-03 04:14:28 +04:00
|
|
|
aOL = PR_TRUE;
|
2001-01-28 23:13:07 +03:00
|
|
|
else if (mHTMLEditor->NodeIsType(curNode,nsIEditProperty::li))
|
2000-05-03 04:14:28 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
PRInt32 offset;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(curNode, address_of(parent), &offset);
|
2000-05-03 04:14:28 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (nsHTMLEditUtils::IsUnorderedList(parent))
|
|
|
|
aUL = PR_TRUE;
|
|
|
|
else if (nsHTMLEditUtils::IsOrderedList(parent))
|
|
|
|
aOL = PR_TRUE;
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
else if (mHTMLEditor->NodeIsType(curNode,nsIEditProperty::dl) ||
|
|
|
|
mHTMLEditor->NodeIsType(curNode,nsIEditProperty::dt) ||
|
|
|
|
mHTMLEditor->NodeIsType(curNode,nsIEditProperty::dd) )
|
2000-06-02 11:47:53 +04:00
|
|
|
{
|
|
|
|
aDL = PR_TRUE;
|
|
|
|
}
|
|
|
|
else bNonList = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// hokey arithmetic with booleans
|
|
|
|
if ( (aUL + aOL + aDL + bNonList) > 1) aMixed = PR_TRUE;
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditRules::GetListItemState(PRBool &aMixed, PRBool &aLI, PRBool &aDT, PRBool &aDD)
|
|
|
|
{
|
|
|
|
aMixed = PR_FALSE;
|
|
|
|
aLI = PR_FALSE;
|
|
|
|
aDT = PR_FALSE;
|
|
|
|
aDD = PR_FALSE;
|
|
|
|
PRBool bNonList = PR_FALSE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
2000-12-09 07:46:08 +03:00
|
|
|
nsresult res = GetListActionNodes(address_of(arrayOfNodes), PR_FALSE, PR_TRUE);
|
2000-06-02 11:47:53 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// examine list type for nodes in selection
|
|
|
|
PRUint32 listCount;
|
|
|
|
PRInt32 i;
|
|
|
|
arrayOfNodes->Count(&listCount);
|
|
|
|
for (i=(PRInt32)listCount-1; i>=0; i--)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
|
|
|
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->NodeIsType(curNode,nsIEditProperty::ul) ||
|
|
|
|
mHTMLEditor->NodeIsType(curNode,nsIEditProperty::ol) ||
|
|
|
|
mHTMLEditor->NodeIsType(curNode,nsIEditProperty::li) )
|
2000-06-02 11:47:53 +04:00
|
|
|
{
|
|
|
|
aLI = PR_TRUE;
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
else if (mHTMLEditor->NodeIsType(curNode,nsIEditProperty::dt))
|
2000-06-02 11:47:53 +04:00
|
|
|
{
|
|
|
|
aDT = PR_TRUE;
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
else if (mHTMLEditor->NodeIsType(curNode,nsIEditProperty::dd))
|
2000-06-02 11:47:53 +04:00
|
|
|
{
|
|
|
|
aDD = PR_TRUE;
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
else if (mHTMLEditor->NodeIsType(curNode,nsIEditProperty::dl))
|
2000-06-02 11:47:53 +04:00
|
|
|
{
|
|
|
|
// need to look inside dl and see which types of items it has
|
|
|
|
PRBool bDT, bDD;
|
|
|
|
res = GetDefinitionListItemTypes(curNode, bDT, bDD);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
aDT |= bDT;
|
|
|
|
aDD |= bDD;
|
|
|
|
}
|
2000-05-03 04:14:28 +04:00
|
|
|
else bNonList = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// hokey arithmetic with booleans
|
2000-06-02 11:47:53 +04:00
|
|
|
if ( (aDT + aDD + bNonList) > 1) aMixed = PR_TRUE;
|
2000-05-03 04:14:28 +04:00
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2000-08-14 16:07:10 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditRules::GetAlignment(PRBool &aMixed, nsIHTMLEditor::EAlignment &aAlign)
|
|
|
|
{
|
2000-08-17 07:59:50 +04:00
|
|
|
// for now, just return first alignment. we'll lie about
|
2000-09-07 18:33:06 +04:00
|
|
|
// if it's mixed. This is for efficiency
|
|
|
|
// given that our current ui doesn't care if it's mixed.
|
|
|
|
// cmanske: NOT TRUE! We would like to pay attention to mixed state
|
|
|
|
// in Format | Align submenu!
|
2000-08-17 07:59:50 +04:00
|
|
|
|
|
|
|
// this routine assumes that alignment is done ONLY via divs
|
|
|
|
|
|
|
|
// default alignment is left
|
2000-08-24 05:20:29 +04:00
|
|
|
aMixed = PR_FALSE;
|
2000-08-17 07:59:50 +04:00
|
|
|
aAlign = nsIHTMLEditor::eLeft;
|
|
|
|
|
|
|
|
// get selection
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection>selection;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
|
2000-08-17 07:59:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// get selection location
|
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
PRInt32 offset;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetStartNodeAndOffset(selection, address_of(parent), &offset);
|
2000-08-17 07:59:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// is the selection collapsed?
|
|
|
|
PRBool bCollapsed;
|
|
|
|
res = selection->GetIsCollapsed(&bCollapsed);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
nsCOMPtr<nsIDOMNode> nodeToExamine;
|
|
|
|
if (bCollapsed)
|
|
|
|
{
|
|
|
|
// if it is, we want to look at 'parent' and it's ancestors
|
|
|
|
// for divs with alignment on them
|
|
|
|
nodeToExamine = parent;
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
else if (mHTMLEditor->IsTextNode(parent))
|
2000-08-17 07:59:50 +04:00
|
|
|
{
|
|
|
|
// if we are in a text node, then that is the node of interest
|
|
|
|
nodeToExamine = parent;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// otherwise we want to look at the first editable node after
|
|
|
|
// {parent,offset} and it's ancestors for divs with alignment on them
|
2001-01-28 23:13:07 +03:00
|
|
|
mHTMLEditor->GetNextNode(parent, offset, PR_TRUE, getter_AddRefs(nodeToExamine));
|
2000-08-17 07:59:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!nodeToExamine) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// check up the ladder for divs with alignment
|
|
|
|
nsCOMPtr<nsIDOMNode> temp = nodeToExamine;
|
|
|
|
while (nodeToExamine)
|
|
|
|
{
|
|
|
|
if (nsHTMLEditUtils::IsDiv(nodeToExamine))
|
|
|
|
{
|
|
|
|
// check for alignment
|
|
|
|
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(nodeToExamine);
|
|
|
|
if (elem)
|
|
|
|
{
|
|
|
|
nsAutoString typeAttrName; typeAttrName.AssignWithConversion("align");
|
|
|
|
nsAutoString typeAttrVal;
|
2000-11-30 01:06:02 +03:00
|
|
|
res = elem->GetAttribute(typeAttrName, typeAttrVal);
|
2000-08-17 07:59:50 +04:00
|
|
|
typeAttrVal.ToLowerCase();
|
|
|
|
if (NS_SUCCEEDED(res) && typeAttrVal.Length())
|
|
|
|
{
|
|
|
|
if (typeAttrVal.EqualsWithConversion("center"))
|
|
|
|
aAlign = nsIHTMLEditor::eCenter;
|
|
|
|
else if (typeAttrVal.EqualsWithConversion("right"))
|
|
|
|
aAlign = nsIHTMLEditor::eRight;
|
2000-08-24 05:20:29 +04:00
|
|
|
else if (typeAttrVal.EqualsWithConversion("justify"))
|
|
|
|
aAlign = nsIHTMLEditor::eJustify;
|
2000-08-17 07:59:50 +04:00
|
|
|
else
|
|
|
|
aAlign = nsIHTMLEditor::eLeft;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
res = nodeToExamine->GetParentNode(getter_AddRefs(temp));
|
|
|
|
if (NS_FAILED(res)) temp = nsnull;
|
|
|
|
nodeToExamine = temp;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
2000-08-14 16:07:10 +04:00
|
|
|
}
|
2000-05-03 04:14:28 +04:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditRules::GetIndentState(PRBool &aCanIndent, PRBool &aCanOutdent)
|
|
|
|
{
|
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
|
|
|
aCanIndent = PR_TRUE;
|
|
|
|
aCanOutdent = PR_FALSE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
2000-12-09 07:46:08 +03:00
|
|
|
nsresult res = GetListActionNodes(address_of(arrayOfNodes), PR_FALSE, PR_TRUE);
|
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;
|
|
|
|
|
|
|
|
// examine nodes in selection for blockquotes or list elements;
|
|
|
|
// these we can outdent. Note that we return true for canOutdent
|
|
|
|
// if *any* of the selection is outdentable, rather than all of it.
|
|
|
|
PRUint32 listCount;
|
|
|
|
PRInt32 i;
|
|
|
|
arrayOfNodes->Count(&listCount);
|
|
|
|
for (i=(PRInt32)listCount-1; i>=0; i--)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
|
|
|
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
|
|
|
|
|
|
|
|
if (nsHTMLEditUtils::IsList(curNode) ||
|
|
|
|
nsHTMLEditUtils::IsListItem(curNode) ||
|
|
|
|
nsHTMLEditUtils::IsBlockquote(curNode))
|
|
|
|
{
|
|
|
|
aCanOutdent = PR_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLEditRules::GetParagraphState(PRBool &aMixed, nsString &outFormat)
|
|
|
|
{
|
|
|
|
// This routine is *heavily* tied to our ui choices in the paragraph
|
|
|
|
// style popup. I cant see a way around that.
|
|
|
|
aMixed = PR_TRUE;
|
|
|
|
outFormat.AssignWithConversion("");
|
|
|
|
|
|
|
|
PRBool bMixed = PR_FALSE;
|
|
|
|
nsAutoString formatStr;
|
Fixed lots of nsbeta3+ bugs: 45756, 47654, 41810,47503,48990, 48995,40204, 42740, 46953, 47646, 47696, 48693, 45899. r=sfraser,jfrancis
2000-08-23 04:29:24 +04:00
|
|
|
// using "x" as an uninitialized value, since "" is meaningful
|
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
|
|
|
formatStr.AssignWithConversion("x");
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
2000-12-09 07:46:08 +03:00
|
|
|
nsresult res = GetParagraphFormatNodes(address_of(arrayOfNodes), PR_TRUE);
|
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-08-26 08:03:50 +04:00
|
|
|
// we might have an empty node list. if so, find selection parent
|
|
|
|
// and put that on the list
|
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
|
|
|
PRUint32 listCount;
|
|
|
|
arrayOfNodes->Count(&listCount);
|
2000-08-26 08:03:50 +04:00
|
|
|
nsCOMPtr<nsISupports> isupports;
|
|
|
|
if (!listCount)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> selNode;
|
|
|
|
PRInt32 selOffset;
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection>selection;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
|
2000-08-26 08:03:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetStartNodeAndOffset(selection, address_of(selNode), &selOffset);
|
2000-08-26 08:03:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
isupports = do_QueryInterface(selNode);
|
|
|
|
if (!isupports) return NS_ERROR_NULL_POINTER;
|
|
|
|
arrayOfNodes->AppendElement(isupports);
|
|
|
|
listCount = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// loop through the nodes in selection and examine their paragraph format
|
|
|
|
PRInt32 i;
|
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
|
|
|
for (i=(PRInt32)listCount-1; i>=0; i--)
|
|
|
|
{
|
2000-08-26 08:03:50 +04:00
|
|
|
isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
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
|
|
|
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
|
|
|
|
|
|
|
|
nsAutoString format;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIAtom> atom = mHTMLEditor->GetTag(curNode);
|
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
|
|
|
if (mHTMLEditor->IsInlineNode(curNode))
|
2000-06-29 13:23:41 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> block = mHTMLEditor->GetBlockNodeParent(curNode);
|
2000-06-29 13:23:41 +04:00
|
|
|
if (block)
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIAtom> blockAtom = mHTMLEditor->GetTag(block);
|
2000-06-29 13:23:41 +04:00
|
|
|
if ( nsIEditProperty::p == blockAtom.get() ||
|
|
|
|
nsIEditProperty::blockquote == blockAtom.get() ||
|
|
|
|
nsIEditProperty::address == blockAtom.get() ||
|
|
|
|
nsIEditProperty::pre == blockAtom.get() )
|
|
|
|
{
|
|
|
|
blockAtom->ToString(format);
|
|
|
|
}
|
|
|
|
else if (nsHTMLEditUtils::IsHeader(block))
|
|
|
|
{
|
|
|
|
nsAutoString tag;
|
|
|
|
nsEditor::GetTagString(block,tag);
|
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
|
|
|
tag.ToLowerCase();
|
2000-06-29 13:23:41 +04:00
|
|
|
format = tag;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
format.AssignWithConversion("");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
format.AssignWithConversion("");
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
else if (nsHTMLEditUtils::IsHeader(curNode))
|
|
|
|
{
|
|
|
|
nsAutoString tag;
|
|
|
|
nsEditor::GetTagString(curNode,tag);
|
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
|
|
|
tag.ToLowerCase();
|
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
|
|
|
format = tag;
|
|
|
|
}
|
2000-06-06 00:26:40 +04:00
|
|
|
else if (nsIEditProperty::p == atom.get() ||
|
|
|
|
nsIEditProperty::blockquote == atom.get() ||
|
|
|
|
nsIEditProperty::address == atom.get() ||
|
2000-06-29 13:23:41 +04:00
|
|
|
nsIEditProperty::pre == atom.get() )
|
2000-06-06 00:26:40 +04:00
|
|
|
{
|
|
|
|
atom->ToString(format);
|
|
|
|
}
|
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 this is the first node, we've found, remember it as the format
|
|
|
|
if (formatStr.EqualsWithConversion("x"))
|
|
|
|
formatStr = format;
|
|
|
|
// else make sure it matches previously found format
|
|
|
|
else if (format != formatStr)
|
|
|
|
{
|
|
|
|
bMixed = PR_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
aMixed = bMixed;
|
|
|
|
outFormat = formatStr;
|
|
|
|
return res;
|
2000-05-03 04:14:28 +04:00
|
|
|
}
|
|
|
|
|
1999-04-05 21:21:59 +04:00
|
|
|
|
|
|
|
/********************************************************
|
1999-04-12 16:01:32 +04:00
|
|
|
* Protected rules methods
|
1999-04-05 21:21:59 +04:00
|
|
|
********************************************************/
|
1999-11-25 03:19:45 +03:00
|
|
|
|
2000-05-06 00:42:36 +04:00
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::WillInsert(nsISelection *aSelection, PRBool *aCancel)
|
2000-05-06 00:42:36 +04:00
|
|
|
{
|
|
|
|
nsresult res = nsTextEditRules::WillInsert(aSelection, aCancel);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
// Adjust selection to prevent insertion after a moz-BR.
|
|
|
|
// this next only works for collapsed selections right now,
|
|
|
|
// because selection is a pain to work with when not collapsed.
|
|
|
|
// (no good way to extend start or end of selection)
|
|
|
|
PRBool bCollapsed;
|
|
|
|
res = aSelection->GetIsCollapsed(&bCollapsed);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!bCollapsed) return NS_OK;
|
|
|
|
|
|
|
|
// if we are after a mozBR in the same block, then move selection
|
|
|
|
// to be before it
|
|
|
|
nsCOMPtr<nsIDOMNode> selNode, priorNode;
|
|
|
|
PRInt32 selOffset;
|
|
|
|
// get the (collapsed) selection location
|
2001-02-04 22:39:56 +03:00
|
|
|
res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(selNode),
|
|
|
|
&selOffset);
|
2001-01-28 23:13:07 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// get prior node
|
2001-02-04 22:39:56 +03:00
|
|
|
res = mHTMLEditor->GetPriorHTMLNode(selNode, selOffset,
|
|
|
|
address_of(priorNode));
|
2001-01-28 23:13:07 +03:00
|
|
|
if (NS_SUCCEEDED(res) && priorNode && nsHTMLEditUtils::IsMozBR(priorNode))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> block1, block2;
|
|
|
|
if (mHTMLEditor->IsBlockNode(selNode)) block1 = selNode;
|
|
|
|
else block1 = mHTMLEditor->GetBlockNodeParent(selNode);
|
|
|
|
block2 = mHTMLEditor->GetBlockNodeParent(priorNode);
|
|
|
|
|
|
|
|
if (block1 != block2) return NS_OK;
|
|
|
|
|
|
|
|
// if we are here then the selection is right after a mozBR
|
|
|
|
// that is in the same block as the selection. We need to move
|
|
|
|
// the selection start to be before the mozBR.
|
2001-02-04 22:39:56 +03:00
|
|
|
res = nsEditor::GetNodeLocation(priorNode, address_of(selNode), &selOffset);
|
2001-01-28 23:13:07 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = aSelection->Collapse(selNode,selOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
2000-05-06 00:42:36 +04:00
|
|
|
// we need to get the doc
|
|
|
|
nsCOMPtr<nsIDOMDocument>doc;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetDocument(getter_AddRefs(doc));
|
2000-05-06 00:42:36 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!doc) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// for every property that is set, insert a new inline style node
|
|
|
|
res = CreateStyleForInsertText(aSelection, doc);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::DidInsert(nsISelection *aSelection, nsresult aResult)
|
2000-05-06 00:42:36 +04:00
|
|
|
{
|
|
|
|
return nsTextEditRules::DidInsert(aSelection, aResult);
|
|
|
|
}
|
1999-11-25 03:19:45 +03:00
|
|
|
|
1999-04-12 16:01:32 +04:00
|
|
|
nsresult
|
1999-11-01 18:15:35 +03:00
|
|
|
nsHTMLEditRules::WillInsertText(PRInt32 aAction,
|
2000-09-14 15:45:01 +04:00
|
|
|
nsISelection *aSelection,
|
1999-04-12 16:01:32 +04:00
|
|
|
PRBool *aCancel,
|
1999-10-06 23:34:09 +04:00
|
|
|
PRBool *aHandled,
|
1999-11-01 18:15:35 +03:00
|
|
|
const nsString *inString,
|
|
|
|
nsString *outString,
|
|
|
|
PRInt32 aMaxLength)
|
1999-11-29 11:28:46 +03:00
|
|
|
{
|
|
|
|
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
1999-08-24 12:56:51 +04:00
|
|
|
|
1999-12-01 17:32:55 +03:00
|
|
|
if (inString->IsEmpty() && (aAction != kInsertTextIME))
|
|
|
|
{
|
|
|
|
// HACK: this is a fix for bug 19395
|
|
|
|
// I can't outlaw all empty insertions
|
|
|
|
// because IME transaction depend on them
|
|
|
|
// There is more work to do to make the
|
|
|
|
// world safe for IME.
|
|
|
|
*aCancel = PR_TRUE;
|
|
|
|
*aHandled = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-04-12 16:01:32 +04:00
|
|
|
// initialize out param
|
1999-10-06 23:34:09 +04:00
|
|
|
*aCancel = PR_FALSE;
|
|
|
|
*aHandled = PR_TRUE;
|
1999-07-02 08:46:45 +04:00
|
|
|
nsresult res;
|
1999-09-30 00:08:15 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> selNode;
|
|
|
|
PRInt32 selOffset;
|
1999-04-12 16:01:32 +04:00
|
|
|
|
1999-09-06 23:51:59 +04:00
|
|
|
// if the selection isn't collapsed, delete it.
|
|
|
|
PRBool bCollapsed;
|
|
|
|
res = aSelection->GetIsCollapsed(&bCollapsed);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!bCollapsed)
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteSelection(nsIEditor::eNone);
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
1999-09-30 00:08:15 +04:00
|
|
|
res = WillInsert(aSelection, aCancel);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// initialize out param
|
|
|
|
// we want to ignore result of WillInsert()
|
1999-10-06 23:34:09 +04:00
|
|
|
*aCancel = PR_FALSE;
|
1999-11-25 03:19:45 +03:00
|
|
|
|
|
|
|
// get the (collapsed) selection location
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-09-30 00:08:15 +04:00
|
|
|
|
2000-01-10 13:13:58 +03:00
|
|
|
// dont put text in places that cant have it
|
2000-04-18 11:52:02 +04:00
|
|
|
nsAutoString textTag; textTag.AssignWithConversion("__moz_text");
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!mHTMLEditor->IsTextNode(selNode) && !mHTMLEditor->CanContainTag(selNode, textTag))
|
2000-01-10 13:13:58 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
// we need to get the doc
|
|
|
|
nsCOMPtr<nsIDOMDocument>doc;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetDocument(getter_AddRefs(doc));
|
2000-03-29 16:53:23 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!doc) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
if (aAction == kInsertTextIME)
|
1999-11-01 18:15:35 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->InsertTextImpl(*inString, address_of(selNode), &selOffset, doc);
|
2000-03-29 16:53:23 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-11-01 18:15:35 +03:00
|
|
|
}
|
|
|
|
else // aAction == kInsertText
|
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
// find where we are
|
|
|
|
nsCOMPtr<nsIDOMNode> curNode = selNode;
|
|
|
|
PRInt32 curOffset = selOffset;
|
|
|
|
|
|
|
|
// is our text going to be PREformatted?
|
|
|
|
// We remember this so that we know how to handle tabs.
|
|
|
|
PRBool isPRE;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->IsPreformatted(selNode, &isPRE);
|
2000-03-24 03:26:47 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// turn off the edit listener: we know how to
|
|
|
|
// build the "doc changed range" ourselves, and it's
|
|
|
|
// must faster to do it once here than to track all
|
|
|
|
// the changes one at a time.
|
|
|
|
nsAutoLockListener lockit(&mListenerEnabled);
|
|
|
|
|
|
|
|
// dont spaz my selection in subtransactions
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
|
2000-03-29 16:53:23 +04:00
|
|
|
nsSubsumeStr subStr;
|
|
|
|
const PRUnichar *unicodeBuf = inString->GetUnicode();
|
2000-03-24 03:26:47 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> unused;
|
2000-03-29 16:53:23 +04:00
|
|
|
PRInt32 pos = 0;
|
2000-03-24 03:26:47 +03:00
|
|
|
|
|
|
|
// for efficiency, break out the pre case seperately. This is because
|
|
|
|
// its a lot cheaper to search the input string for only newlines than
|
|
|
|
// it is to search for both tabs and newlines.
|
|
|
|
if (isPRE)
|
1999-09-12 05:36:07 +04:00
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
char newlineChar = '\n';
|
2000-06-06 00:26:40 +04:00
|
|
|
while (unicodeBuf && (pos != -1) && (pos < (PRInt32)inString->Length()))
|
1999-11-01 18:15:35 +03:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
PRInt32 oldPos = pos;
|
|
|
|
PRInt32 subStrLen;
|
|
|
|
pos = inString->FindChar(newlineChar, PR_FALSE, oldPos);
|
|
|
|
|
|
|
|
if (pos != -1)
|
|
|
|
{
|
|
|
|
subStrLen = pos - oldPos;
|
|
|
|
// if first char is newline, then use just it
|
|
|
|
if (subStrLen == 0)
|
|
|
|
subStrLen = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
subStrLen = inString->Length() - oldPos;
|
|
|
|
pos = inString->Length();
|
|
|
|
}
|
|
|
|
|
|
|
|
subStr.Subsume((PRUnichar*)&unicodeBuf[oldPos], PR_FALSE, subStrLen);
|
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
// is it a return?
|
2000-04-18 11:52:02 +04:00
|
|
|
if (subStr.EqualsWithConversion("\n"))
|
2000-03-24 03:26:47 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateBRImpl(address_of(curNode), &curOffset, address_of(unused), nsIEditor::eNone);
|
2000-03-29 16:53:23 +04:00
|
|
|
pos++;
|
2000-03-24 03:26:47 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->InsertTextImpl(subStr, address_of(curNode), &curOffset, doc);
|
2000-03-24 03:26:47 +03:00
|
|
|
}
|
1999-11-01 18:15:35 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
2000-03-24 03:26:47 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char specialChars[] = {'\t','\n',0};
|
2000-04-18 11:52:02 +04:00
|
|
|
nsAutoString tabString; tabString.AssignWithConversion(" ");
|
2000-06-06 00:26:40 +04:00
|
|
|
while (unicodeBuf && (pos != -1) && (pos < (PRInt32)inString->Length()))
|
1999-11-01 18:15:35 +03:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
PRInt32 oldPos = pos;
|
|
|
|
PRInt32 subStrLen;
|
|
|
|
pos = inString->FindCharInSet(specialChars, oldPos);
|
|
|
|
|
|
|
|
if (pos != -1)
|
|
|
|
{
|
|
|
|
subStrLen = pos - oldPos;
|
|
|
|
// if first char is newline, then use just it
|
|
|
|
if (subStrLen == 0)
|
|
|
|
subStrLen = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
subStrLen = inString->Length() - oldPos;
|
|
|
|
pos = inString->Length();
|
|
|
|
}
|
|
|
|
|
|
|
|
subStr.Subsume((PRUnichar*)&unicodeBuf[oldPos], PR_FALSE, subStrLen);
|
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
// is it a tab?
|
2000-04-18 11:52:02 +04:00
|
|
|
if (subStr.EqualsWithConversion("\t"))
|
2000-03-24 03:26:47 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->InsertTextImpl(tabString, address_of(curNode), &curOffset, doc);
|
2000-03-29 16:53:23 +04:00
|
|
|
pos++;
|
2000-03-24 03:26:47 +03:00
|
|
|
}
|
|
|
|
// is it a return?
|
2000-04-18 11:52:02 +04:00
|
|
|
else if (subStr.EqualsWithConversion("\n"))
|
2000-03-24 03:26:47 +03:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateBRImpl(address_of(curNode), &curOffset, address_of(unused), nsIEditor::eNone);
|
2000-03-29 16:53:23 +04:00
|
|
|
pos++;
|
2000-03-24 03:26:47 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->InsertTextImpl(subStr, address_of(curNode), &curOffset, doc);
|
2000-03-24 03:26:47 +03:00
|
|
|
}
|
|
|
|
if (NS_FAILED(res)) return res;
|
1999-11-01 18:15:35 +03:00
|
|
|
}
|
2000-03-24 03:26:47 +03:00
|
|
|
}
|
|
|
|
if (curNode) aSelection->Collapse(curNode, curOffset);
|
|
|
|
// manually update the doc changed range so that AfterEdit will clean up
|
|
|
|
// the correct portion of the document.
|
|
|
|
if (!mDocChangeRange)
|
|
|
|
{
|
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
|
|
|
mDocChangeRange = do_CreateInstance(kRangeCID);
|
|
|
|
if (!mDocChangeRange) return NS_ERROR_NULL_POINTER;
|
1999-09-12 05:36:07 +04:00
|
|
|
}
|
2000-03-24 03:26:47 +03:00
|
|
|
res = mDocChangeRange->SetStart(selNode, selOffset);
|
|
|
|
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
|
|
|
if (curNode)
|
|
|
|
res = mDocChangeRange->SetEnd(curNode, curOffset);
|
|
|
|
else
|
|
|
|
res = mDocChangeRange->SetEnd(selNode, selOffset);
|
2000-03-24 03:26:47 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-09-12 05:36:07 +04:00
|
|
|
}
|
1999-07-02 08:46:45 +04:00
|
|
|
return res;
|
1999-04-12 16:01:32 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled)
|
1999-03-29 10:21:01 +04:00
|
|
|
{
|
1999-10-06 23:34:09 +04:00
|
|
|
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection> selection(aSelection);
|
|
|
|
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
|
1999-03-29 10:21:01 +04:00
|
|
|
// initialize out param
|
|
|
|
*aCancel = PR_FALSE;
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_FALSE;
|
1999-04-26 18:08:52 +04:00
|
|
|
|
1999-09-06 23:51:59 +04:00
|
|
|
|
1999-04-26 18:08:52 +04:00
|
|
|
// if the selection isn't collapsed, delete it.
|
|
|
|
PRBool bCollapsed;
|
1999-11-29 11:28:46 +03:00
|
|
|
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
|
1999-04-26 18:08:52 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!bCollapsed)
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteSelection(nsIEditor::eNone);
|
1999-04-26 18:08:52 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
1999-11-29 11:28:46 +03:00
|
|
|
res = WillInsert(aSelection, aCancel);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// initialize out param
|
|
|
|
// we want to ignore result of WillInsert()
|
|
|
|
*aCancel = PR_FALSE;
|
2001-01-28 23:13:07 +03:00
|
|
|
|
|
|
|
// split any mailcites in the way.
|
|
|
|
// should we abort this if we encounter table cell boundaries?
|
|
|
|
if (mFlags & nsIPlaintextEditor::eEditorMailMask)
|
1999-09-20 05:31:44 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> citeNode, selNode;
|
|
|
|
PRInt32 selOffset, newOffset;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
|
1999-09-20 05:31:44 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
PRBool bPlaintext = mFlags & nsIPlaintextEditor::eEditorPlaintextMask;
|
|
|
|
res = GetTopEnclosingMailCite(selNode, address_of(citeNode), bPlaintext);
|
1999-09-20 05:31:44 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (citeNode)
|
|
|
|
{
|
2000-05-06 01:22:09 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> brNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SplitNodeDeep(citeNode, selNode, selOffset, &newOffset);
|
1999-09-20 05:31:44 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = citeNode->GetParentNode(getter_AddRefs(selNode));
|
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateBR(selNode, newOffset, address_of(brNode));
|
2000-05-06 01:22:09 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// want selection before the break, and on same line
|
2000-09-14 15:45:01 +04:00
|
|
|
selPriv->SetInterlinePosition(PR_TRUE);
|
1999-09-20 05:31:44 +04:00
|
|
|
res = aSelection->Collapse(selNode, newOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-05-06 01:22:09 +04:00
|
|
|
*aHandled = PR_TRUE;
|
|
|
|
return NS_OK;
|
1999-09-20 05:31:44 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-08-24 12:56:51 +04:00
|
|
|
// smart splitting rules
|
1999-04-26 18:08:52 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
PRInt32 offset;
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(node), &offset);
|
1999-04-26 18:08:52 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!node) return NS_ERROR_FAILURE;
|
|
|
|
|
1999-09-30 00:08:15 +04:00
|
|
|
// identify the block
|
1999-08-18 12:13:06 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> blockParent;
|
|
|
|
|
|
|
|
if (nsEditor::IsBlockNode(node))
|
|
|
|
blockParent = node;
|
|
|
|
else
|
2001-01-28 23:13:07 +03:00
|
|
|
blockParent = mHTMLEditor->GetBlockNodeParent(node);
|
1999-08-18 12:13:06 +04:00
|
|
|
|
1999-04-26 18:08:52 +04:00
|
|
|
if (!blockParent) return NS_ERROR_FAILURE;
|
|
|
|
|
1999-08-24 12:56:51 +04:00
|
|
|
// headers: close (or split) header
|
2000-01-26 03:57:37 +03:00
|
|
|
else if (nsHTMLEditUtils::IsHeader(blockParent))
|
1999-04-26 18:08:52 +04:00
|
|
|
{
|
|
|
|
res = ReturnInHeader(aSelection, blockParent, node, offset);
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_TRUE;
|
1999-04-26 18:08:52 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// paragraphs: special rules to look for <br>s
|
2000-01-26 03:57:37 +03:00
|
|
|
else if (nsHTMLEditUtils::IsParagraph(blockParent))
|
1999-04-26 18:08:52 +04:00
|
|
|
{
|
1999-10-06 23:34:09 +04:00
|
|
|
res = ReturnInParagraph(aSelection, blockParent, node, offset, aCancel, aHandled);
|
1999-04-26 18:08:52 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// list items: special rules to make new list items
|
2000-01-26 03:57:37 +03:00
|
|
|
else if (nsHTMLEditUtils::IsListItem(blockParent))
|
1999-04-26 18:08:52 +04:00
|
|
|
{
|
|
|
|
res = ReturnInListItem(aSelection, blockParent, node, offset);
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_TRUE;
|
1999-04-26 18:08:52 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-11-25 03:19:45 +03:00
|
|
|
// its something else (body, div, td, ...): insert a normal br
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> brNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateBR(node, offset, address_of(brNode));
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(brNode, address_of(node), &offset);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-09-14 15:45:01 +04:00
|
|
|
// SetInterlinePosition(PR_TRUE) means we want the caret to stick to the content on the "right".
|
2000-05-06 01:22:09 +04:00
|
|
|
// We want the caret to stick to whatever is past the break. This is
|
|
|
|
// because the break is on the same line we were on, but the next content
|
|
|
|
// will be on the following line.
|
|
|
|
|
|
|
|
// An exception to this is if the break has a next sibling that is a block node.
|
|
|
|
// Then we stick to the left to aviod an uber caret.
|
|
|
|
nsCOMPtr<nsIDOMNode> siblingNode;
|
|
|
|
brNode->GetNextSibling(getter_AddRefs(siblingNode));
|
2001-01-28 23:13:07 +03:00
|
|
|
if (siblingNode && mHTMLEditor->IsBlockNode(siblingNode))
|
2000-09-14 15:45:01 +04:00
|
|
|
selPriv->SetInterlinePosition(PR_FALSE);
|
2000-05-06 01:22:09 +04:00
|
|
|
else
|
2000-09-14 15:45:01 +04:00
|
|
|
selPriv->SetInterlinePosition(PR_TRUE);
|
1999-11-25 03:19:45 +03:00
|
|
|
res = aSelection->Collapse(node, offset+1);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
*aHandled = PR_TRUE;
|
|
|
|
}
|
1999-04-26 18:08:52 +04:00
|
|
|
|
1999-08-24 12:56:51 +04:00
|
|
|
return res;
|
1999-03-29 10:21:01 +04:00
|
|
|
}
|
|
|
|
|
1999-04-26 18:08:52 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::DidInsertBreak(nsISelection *aSelection, nsresult aResult)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-04-26 18:08:52 +04:00
|
|
|
|
1999-04-12 16:01:32 +04:00
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
|
1999-12-07 11:30:19 +03:00
|
|
|
nsIEditor::EDirection aAction,
|
1999-10-06 23:34:09 +04:00
|
|
|
PRBool *aCancel,
|
|
|
|
PRBool *aHandled)
|
1999-04-26 18:08:52 +04:00
|
|
|
{
|
1999-10-06 23:34:09 +04:00
|
|
|
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
1999-04-26 18:08:52 +04:00
|
|
|
// initialize out param
|
|
|
|
*aCancel = PR_FALSE;
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_FALSE;
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection> selection(aSelection);
|
|
|
|
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
|
1999-04-26 18:08:52 +04:00
|
|
|
|
1999-09-06 23:51:59 +04:00
|
|
|
// if there is only bogus content, cancel the operation
|
|
|
|
if (mBogusNode)
|
|
|
|
{
|
|
|
|
*aCancel = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-04-26 18:08:52 +04:00
|
|
|
nsresult res = NS_OK;
|
|
|
|
|
|
|
|
PRBool bCollapsed;
|
1999-07-18 06:27:19 +04:00
|
|
|
res = aSelection->GetIsCollapsed(&bCollapsed);
|
1999-04-26 18:08:52 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2000-08-28 09:11:49 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> startNode, selNode;
|
|
|
|
PRInt32 startOffset, selOffset;
|
1999-04-26 18:08:52 +04:00
|
|
|
|
2000-08-28 09:11:49 +04:00
|
|
|
// first check for table selection mode. If so,
|
|
|
|
// hand off to table editor.
|
|
|
|
nsCOMPtr<nsIDOMElement> cell;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetFirstSelectedCell(getter_AddRefs(cell), nsnull);
|
2000-08-28 09:11:49 +04:00
|
|
|
if (NS_SUCCEEDED(res) && cell)
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteTableCellContents();
|
2000-08-28 09:11:49 +04:00
|
|
|
*aHandled = PR_TRUE;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(startNode), &startOffset);
|
1999-04-26 18:08:52 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-08-28 09:11:49 +04:00
|
|
|
if (!startNode) return NS_ERROR_FAILURE;
|
1999-04-26 18:08:52 +04:00
|
|
|
|
|
|
|
if (bCollapsed)
|
|
|
|
{
|
|
|
|
// easy case, in a text node:
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->IsTextNode(startNode))
|
1999-03-29 10:21:01 +04:00
|
|
|
{
|
2000-08-28 09:11:49 +04:00
|
|
|
nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(startNode);
|
1999-04-26 18:08:52 +04:00
|
|
|
PRUint32 strLength;
|
|
|
|
res = textNode->GetLength(&strLength);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// at beginning of text node and backspaced?
|
2000-08-28 09:11:49 +04:00
|
|
|
if (!startOffset && (aAction == nsIEditor::ePrevious))
|
1999-04-26 18:08:52 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> priorNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetPriorHTMLNode(startNode, address_of(priorNode));
|
1999-04-26 18:08:52 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
1999-09-12 05:36:07 +04:00
|
|
|
// if there is no prior node then cancel the deletion
|
|
|
|
if (!priorNode)
|
1999-05-01 23:37:50 +04:00
|
|
|
{
|
|
|
|
*aCancel = PR_TRUE;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
// block parents the same?
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->HasSameBlockNodeParent(startNode, priorNode))
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
// is prior node not a container? (ie, a br, hr, image...)
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!mHTMLEditor->IsContainer(priorNode)) // MOOSE: anchors not handled
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
// delete the break, and join like nodes if appropriate
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(priorNode);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-01-15 17:29:29 +03:00
|
|
|
// we did something, so lets say so.
|
|
|
|
*aHandled = PR_TRUE;
|
1999-11-25 03:19:45 +03:00
|
|
|
// get new prior node
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetPriorHTMLNode(startNode, address_of(priorNode));
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// are they in same block?
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->HasSameBlockNodeParent(startNode, priorNode))
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
// are they same type?
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->IsTextNode(priorNode))
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
// if so, join them!
|
2000-01-10 13:13:58 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> topParent;
|
|
|
|
priorNode->GetParentNode(getter_AddRefs(topParent));
|
2000-12-09 07:46:08 +03:00
|
|
|
res = JoinNodesSmart(priorNode,startNode,address_of(selNode),&selOffset);
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// fix up selection
|
|
|
|
res = aSelection->Collapse(selNode,selOffset);
|
1999-11-25 03:19:45 +03:00
|
|
|
}
|
|
|
|
}
|
2000-06-10 06:25:50 +04:00
|
|
|
return res;
|
1999-11-25 03:19:45 +03:00
|
|
|
}
|
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
|
|
|
// is prior node a text node?
|
2001-01-28 23:13:07 +03:00
|
|
|
else if ( mHTMLEditor->IsTextNode(priorNode) )
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
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
|
|
|
// delete last character
|
2000-08-28 09:11:49 +04:00
|
|
|
PRUint32 offset;
|
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
|
|
|
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
|
|
|
nodeAsText = do_QueryInterface(priorNode);
|
|
|
|
nodeAsText->GetLength((PRUint32*)&offset);
|
|
|
|
res = aSelection->Collapse(priorNode,offset);
|
|
|
|
// just return without setting handled to true.
|
|
|
|
// default code will take care of actual deletion
|
|
|
|
return res;
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
else if ( mHTMLEditor->IsInlineNode(priorNode) )
|
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
|
|
|
{
|
|
|
|
// remember where we are
|
2000-08-28 09:11:49 +04:00
|
|
|
PRInt32 offset;
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNodeLocation(priorNode, address_of(node), &offset);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
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
|
|
|
// delete it
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(priorNode);
|
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;
|
|
|
|
// we did something, so lets say so.
|
|
|
|
*aHandled = PR_TRUE;
|
1999-11-25 03:19:45 +03:00
|
|
|
// fix up selection
|
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
|
|
|
res = aSelection->Collapse(node,offset);
|
1999-11-25 03:19:45 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
else return NS_OK; // punt to default
|
|
|
|
}
|
1999-06-16 09:02:43 +04:00
|
|
|
|
|
|
|
// deleting across blocks
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> leftParent = mHTMLEditor->GetBlockNodeParent(priorNode);
|
|
|
|
nsCOMPtr<nsIDOMNode> rightParent = mHTMLEditor->GetBlockNodeParent(startNode);
|
1999-09-06 23:51:59 +04:00
|
|
|
|
|
|
|
// if leftParent or rightParent is null, it's because the
|
|
|
|
// corresponding selection endpoint is in the body node.
|
|
|
|
if (!leftParent || !rightParent)
|
|
|
|
return NS_OK; // bail to default
|
|
|
|
|
1999-12-01 17:32:55 +03:00
|
|
|
// do not delete across table structures
|
2000-08-14 03:53:34 +04:00
|
|
|
if (nsHTMLEditUtils::IsTableElement(leftParent) || nsHTMLEditUtils::IsTableElement(rightParent))
|
1999-12-01 17:32:55 +03:00
|
|
|
{
|
|
|
|
*aCancel = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// are the blocks of same type?
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->NodesSameType(leftParent, rightParent))
|
1999-06-16 09:02:43 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> topParent;
|
|
|
|
leftParent->GetParentNode(getter_AddRefs(topParent));
|
|
|
|
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_TRUE;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = JoinNodesSmart(leftParent,rightParent,address_of(selNode),&selOffset);
|
1999-09-02 01:23:47 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// fix up selection
|
|
|
|
res = aSelection->Collapse(selNode,selOffset);
|
|
|
|
return res;
|
1999-06-16 09:02:43 +04:00
|
|
|
}
|
1999-04-26 18:08:52 +04:00
|
|
|
|
|
|
|
// else blocks not same type, bail to default
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// at end of text node and deleted?
|
2000-08-28 09:11:49 +04:00
|
|
|
if ((startOffset == (PRInt32)strLength)
|
1999-12-07 11:30:19 +03:00
|
|
|
&& (aAction == nsIEditor::eNext))
|
1999-03-29 10:21:01 +04:00
|
|
|
{
|
1999-04-26 18:08:52 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> nextNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNextHTMLNode(startNode, address_of(nextNode));
|
1999-04-26 18:08:52 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-05-01 23:37:50 +04:00
|
|
|
|
1999-09-10 02:22:14 +04:00
|
|
|
// if there is no next node, or it's not in the body, then cancel the deletion
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!nextNode || !nsHTMLEditUtils::InBody(nextNode, mHTMLEditor))
|
1999-05-01 23:37:50 +04:00
|
|
|
{
|
|
|
|
*aCancel = PR_TRUE;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
// block parents the same?
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->HasSameBlockNodeParent(startNode, nextNode))
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
// is next node not a container? (ie, a br, hr, image...)
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!mHTMLEditor->IsContainer(nextNode)) // MOOSE: anchors not handled
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
// delete the break, and join like nodes if appropriate
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(nextNode);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-01-15 17:29:29 +03:00
|
|
|
// we did something, so lets say so.
|
|
|
|
*aHandled = PR_TRUE;
|
1999-11-25 03:19:45 +03:00
|
|
|
// get new next node
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNextHTMLNode(startNode, address_of(nextNode));
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// are they in same block?
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->HasSameBlockNodeParent(startNode, nextNode))
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
// are they same type?
|
2001-01-28 23:13:07 +03:00
|
|
|
if ( mHTMLEditor->IsTextNode(nextNode) )
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
// if so, join them!
|
2000-01-10 13:13:58 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> topParent;
|
|
|
|
nextNode->GetParentNode(getter_AddRefs(topParent));
|
2000-12-09 07:46:08 +03:00
|
|
|
res = JoinNodesSmart(startNode,nextNode,address_of(selNode),&selOffset);
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// fix up selection
|
|
|
|
res = aSelection->Collapse(selNode,selOffset);
|
1999-11-25 03:19:45 +03:00
|
|
|
}
|
|
|
|
}
|
2000-06-10 06:25:50 +04:00
|
|
|
return res;
|
1999-11-25 03:19:45 +03:00
|
|
|
}
|
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
|
|
|
// is next node a text node?
|
2001-01-28 23:13:07 +03:00
|
|
|
else if ( mHTMLEditor->IsTextNode(nextNode) )
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
2000-06-02 10:03:46 +04:00
|
|
|
// delete first character
|
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
|
|
|
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
|
|
|
nodeAsText = do_QueryInterface(nextNode);
|
2000-06-02 10:03:46 +04:00
|
|
|
res = aSelection->Collapse(nextNode,0);
|
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
|
|
|
// just return without setting handled to true.
|
|
|
|
// default code will take care of actual deletion
|
|
|
|
return res;
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
else if ( mHTMLEditor->IsInlineNode(nextNode) )
|
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
|
|
|
{
|
2000-08-28 09:11:49 +04:00
|
|
|
PRInt32 offset;
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
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
|
|
|
// remember where we are
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNodeLocation(nextNode, address_of(node), &offset);
|
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;
|
|
|
|
// delete it
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(nextNode);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
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
|
|
|
// we did something, so lets say so.
|
|
|
|
*aHandled = PR_TRUE;
|
1999-11-25 03:19:45 +03:00
|
|
|
// fix up selection
|
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
|
|
|
res = aSelection->Collapse(node,offset);
|
1999-11-25 03:19:45 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
else return NS_OK; // punt to default
|
|
|
|
}
|
|
|
|
|
1999-06-16 09:02:43 +04:00
|
|
|
// deleting across blocks
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> leftParent = mHTMLEditor->GetBlockNodeParent(startNode);
|
|
|
|
nsCOMPtr<nsIDOMNode> rightParent = mHTMLEditor->GetBlockNodeParent(nextNode);
|
1999-12-01 17:32:55 +03:00
|
|
|
|
|
|
|
// if leftParent or rightParent is null, it's because the
|
|
|
|
// corresponding selection endpoint is in the body node.
|
|
|
|
if (!leftParent || !rightParent)
|
|
|
|
return NS_OK; // bail to default
|
|
|
|
|
|
|
|
// do not delete across table structures
|
2000-08-14 03:53:34 +04:00
|
|
|
if (nsHTMLEditUtils::IsTableElement(leftParent) || nsHTMLEditUtils::IsTableElement(rightParent))
|
1999-12-01 17:32:55 +03:00
|
|
|
{
|
|
|
|
*aCancel = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// are the blocks of same type?
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->NodesSameType(leftParent, rightParent))
|
1999-06-16 09:02:43 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> topParent;
|
|
|
|
leftParent->GetParentNode(getter_AddRefs(topParent));
|
|
|
|
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_TRUE;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = JoinNodesSmart(leftParent,rightParent,address_of(selNode),&selOffset);
|
1999-09-02 01:23:47 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// fix up selection
|
|
|
|
res = aSelection->Collapse(selNode,selOffset);
|
|
|
|
return res;
|
1999-06-16 09:02:43 +04:00
|
|
|
}
|
1999-04-26 18:08:52 +04:00
|
|
|
|
|
|
|
// else blocks not same type, bail to default
|
|
|
|
return NS_OK;
|
|
|
|
|
1999-03-29 10:21:01 +04:00
|
|
|
}
|
|
|
|
}
|
1999-08-31 17:55:18 +04:00
|
|
|
// else not in text node; we need to find right place to act on
|
|
|
|
else
|
|
|
|
{
|
1999-09-06 23:51:59 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> nodeToDelete;
|
1999-08-31 17:55:18 +04:00
|
|
|
|
2000-01-17 15:41:34 +03:00
|
|
|
// first note that the right node to delete might be the one we
|
|
|
|
// are in. For example, if a list item is deleted one character at a time,
|
|
|
|
// eventually it will be empty (except for a moz-br). If the user hits
|
|
|
|
// backspace again, they expect the item itself to go away. Check to
|
|
|
|
// see if we are in an "empty" node.
|
|
|
|
// Note: do NOT delete table elements this way.
|
|
|
|
PRBool bIsEmptyNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->IsEmptyNode(startNode, &bIsEmptyNode, PR_TRUE, PR_FALSE);
|
2000-08-28 09:11:49 +04:00
|
|
|
if (bIsEmptyNode && !nsHTMLEditUtils::IsTableElement(startNode))
|
|
|
|
nodeToDelete = startNode;
|
2000-06-10 06:25:50 +04:00
|
|
|
else
|
|
|
|
{
|
2000-08-28 09:11:49 +04:00
|
|
|
// see if we are on empty line and need to delete it. This is true
|
2000-06-10 06:25:50 +04:00
|
|
|
// when a break is after a block and we are deleting backwards; or
|
|
|
|
// when a break is before a block and we are delting forwards. In
|
|
|
|
// these cases, we want to delete the break when we are between it
|
|
|
|
// and the block element, even though the break is on the "wrong"
|
|
|
|
// side of us.
|
|
|
|
nsCOMPtr<nsIDOMNode> maybeBreak;
|
|
|
|
nsCOMPtr<nsIDOMNode> maybeBlock;
|
1999-09-06 23:51:59 +04:00
|
|
|
|
2000-06-10 06:25:50 +04:00
|
|
|
if (aAction == nsIEditor::ePrevious)
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetPriorHTMLSibling(startNode, startOffset, address_of(maybeBlock));
|
2000-06-10 06:25:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNextHTMLSibling(startNode, startOffset, address_of(maybeBreak));
|
2000-06-10 06:25:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
else if (aAction == nsIEditor::eNext)
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetPriorHTMLSibling(startNode, startOffset, address_of(maybeBreak));
|
2000-06-10 06:25:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNextHTMLSibling(startNode, startOffset, address_of(maybeBlock));
|
2000-06-10 06:25:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
2000-08-26 08:03:50 +04:00
|
|
|
if (maybeBreak && maybeBlock &&
|
|
|
|
nsHTMLEditUtils::IsBreak(maybeBreak) && nsEditor::IsBlockNode(maybeBlock))
|
2000-06-10 06:25:50 +04:00
|
|
|
nodeToDelete = maybeBreak;
|
|
|
|
else if (aAction == nsIEditor::ePrevious)
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetPriorHTMLNode(startNode, startOffset, address_of(nodeToDelete));
|
2000-06-10 06:25:50 +04:00
|
|
|
else if (aAction == nsIEditor::eNext)
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNextHTMLNode(startNode, startOffset, address_of(nodeToDelete));
|
2000-06-10 06:25:50 +04:00
|
|
|
else
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-08-31 17:55:18 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-09-06 23:51:59 +04:00
|
|
|
if (!nodeToDelete) return NS_ERROR_NULL_POINTER;
|
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 (mBody == nodeToDelete)
|
|
|
|
{
|
|
|
|
*aCancel = PR_TRUE;
|
|
|
|
return res;
|
|
|
|
}
|
1999-08-31 17:55:18 +04:00
|
|
|
|
|
|
|
// if this node is text node, adjust selection
|
1999-09-06 23:51:59 +04:00
|
|
|
if (nsEditor::IsTextNode(nodeToDelete))
|
1999-08-31 17:55:18 +04:00
|
|
|
{
|
1999-09-06 23:51:59 +04:00
|
|
|
PRUint32 selPoint = 0;
|
1999-08-31 17:55:18 +04:00
|
|
|
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
1999-09-06 23:51:59 +04:00
|
|
|
nodeAsText = do_QueryInterface(nodeToDelete);
|
1999-12-07 11:30:19 +03:00
|
|
|
if (aAction == nsIEditor::ePrevious)
|
1999-09-06 23:51:59 +04:00
|
|
|
nodeAsText->GetLength(&selPoint);
|
|
|
|
res = aSelection->Collapse(nodeToDelete,selPoint);
|
1999-08-31 17:55:18 +04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// editable leaf node is not text; delete it.
|
|
|
|
// that's the default behavior
|
2000-08-28 09:11:49 +04:00
|
|
|
PRInt32 offset;
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(nodeToDelete, address_of(node), &offset);
|
1999-08-31 17:55:18 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-11-25 03:19:45 +03:00
|
|
|
// EXCEPTION: if it's a mozBR, we have to check and see if
|
|
|
|
// there is a br in front of it. If so, we must delete both.
|
|
|
|
// else you get this: deletion code deletes mozBR, then selection
|
|
|
|
// adjusting code puts it back in. doh
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsMozBR(nodeToDelete))
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> brNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetPriorHTMLNode(nodeToDelete, address_of(brNode));
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsBreak(brNode))
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
2000-01-10 13:13:58 +03:00
|
|
|
// is brNode also a descendant of same block?
|
|
|
|
nsCOMPtr<nsIDOMNode> block, brBlock;
|
2001-01-28 23:13:07 +03:00
|
|
|
block = mHTMLEditor->GetBlockNodeParent(nodeToDelete);
|
|
|
|
brBlock = mHTMLEditor->GetBlockNodeParent(brNode);
|
2000-01-10 13:13:58 +03:00
|
|
|
if (block == brBlock)
|
|
|
|
{
|
|
|
|
// delete both breaks
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(brNode);
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(nodeToDelete);
|
1999-11-25 03:19:45 +03:00
|
|
|
*aHandled = PR_TRUE;
|
2000-01-10 13:13:58 +03:00
|
|
|
return res;
|
1999-11-25 03:19:45 +03:00
|
|
|
}
|
|
|
|
// else fall through
|
|
|
|
}
|
|
|
|
// else fall through
|
|
|
|
}
|
|
|
|
// adjust selection to be right after it
|
1999-08-31 17:55:18 +04:00
|
|
|
res = aSelection->Collapse(node, offset+1);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(nodeToDelete);
|
2000-01-10 13:13:58 +03:00
|
|
|
*aHandled = PR_TRUE;
|
1999-08-31 17:55:18 +04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-08-24 12:56:51 +04:00
|
|
|
return NS_OK;
|
1999-03-29 10:21:01 +04:00
|
|
|
}
|
1999-04-26 18:08:52 +04:00
|
|
|
|
|
|
|
// else we have a non collapsed selection
|
|
|
|
// figure out if the enpoints are in nodes that can be merged
|
|
|
|
nsCOMPtr<nsIDOMNode> endNode;
|
|
|
|
PRInt32 endOffset;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetEndNodeAndOffset(aSelection, address_of(endNode), &endOffset);
|
1999-07-15 23:13:46 +04:00
|
|
|
if (NS_FAILED(res))
|
|
|
|
{
|
|
|
|
return res;
|
|
|
|
}
|
2000-08-28 09:11:49 +04:00
|
|
|
if (endNode.get() != startNode.get())
|
1999-04-26 18:08:52 +04:00
|
|
|
{
|
1999-06-16 09:02:43 +04:00
|
|
|
// block parents the same? use default deletion
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->HasSameBlockNodeParent(startNode, endNode)) return NS_OK;
|
1999-06-16 09:02:43 +04:00
|
|
|
|
|
|
|
// deleting across blocks
|
|
|
|
// are the blocks of same type?
|
1999-08-04 22:36:19 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> leftParent;
|
|
|
|
nsCOMPtr<nsIDOMNode> rightParent;
|
|
|
|
|
|
|
|
// XXX: Fix for bug #10815: Crash deleting selected text and table.
|
|
|
|
// Make sure leftParent and rightParent are never NULL. This
|
|
|
|
// can happen if we call GetBlockNodeParent() and the node we
|
|
|
|
// pass in is a body node.
|
|
|
|
//
|
|
|
|
// Should we be calling IsBlockNode() instead of IsBody() here?
|
|
|
|
|
2000-08-28 09:11:49 +04:00
|
|
|
if (nsHTMLEditUtils::IsBody(startNode))
|
|
|
|
leftParent = startNode;
|
1999-08-04 22:36:19 +04:00
|
|
|
else
|
2001-01-28 23:13:07 +03:00
|
|
|
leftParent = mHTMLEditor->GetBlockNodeParent(startNode);
|
1999-08-04 22:36:19 +04:00
|
|
|
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsBody(endNode))
|
1999-08-04 22:36:19 +04:00
|
|
|
rightParent = endNode;
|
|
|
|
else
|
2001-01-28 23:13:07 +03:00
|
|
|
rightParent = mHTMLEditor->GetBlockNodeParent(endNode);
|
1999-06-16 09:02:43 +04:00
|
|
|
|
|
|
|
// are the blocks siblings?
|
|
|
|
nsCOMPtr<nsIDOMNode> leftBlockParent;
|
|
|
|
nsCOMPtr<nsIDOMNode> rightBlockParent;
|
|
|
|
leftParent->GetParentNode(getter_AddRefs(leftBlockParent));
|
|
|
|
rightParent->GetParentNode(getter_AddRefs(rightBlockParent));
|
|
|
|
|
2000-08-28 09:11:49 +04:00
|
|
|
// MOOSE: this could conceivably screw up a table.. fix me.
|
|
|
|
if ( (leftBlockParent.get() == rightBlockParent.get())
|
2001-01-28 23:13:07 +03:00
|
|
|
&& (mHTMLEditor->NodesSameType(leftParent, rightParent)) )
|
1999-06-16 09:02:43 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> topParent;
|
|
|
|
leftParent->GetParentNode(getter_AddRefs(topParent));
|
|
|
|
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsParagraph(leftParent))
|
1999-06-16 09:02:43 +04:00
|
|
|
{
|
|
|
|
// first delete the selection
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_TRUE;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteSelectionImpl(aAction);
|
1999-04-26 18:08:52 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-06-16 09:02:43 +04:00
|
|
|
// then join para's, insert break
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset);
|
1999-04-26 18:08:52 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-08-31 17:55:18 +04:00
|
|
|
// fix up selection
|
|
|
|
res = aSelection->Collapse(selNode,selOffset);
|
1999-04-26 18:08:52 +04:00
|
|
|
return res;
|
1999-06-16 09:02:43 +04:00
|
|
|
}
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsListItem(leftParent)
|
|
|
|
|| nsHTMLEditUtils::IsHeader(leftParent))
|
1999-06-16 09:02:43 +04:00
|
|
|
{
|
|
|
|
// first delete the selection
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_TRUE;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteSelectionImpl(aAction);
|
1999-04-26 18:08:52 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-06-16 09:02:43 +04:00
|
|
|
// join blocks
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset);
|
1999-08-31 17:55:18 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// fix up selection
|
|
|
|
res = aSelection->Collapse(selNode,selOffset);
|
1999-04-26 18:08:52 +04:00
|
|
|
return res;
|
1999-06-16 09:02:43 +04:00
|
|
|
}
|
|
|
|
}
|
1999-04-26 18:08:52 +04:00
|
|
|
|
2000-08-28 09:11:49 +04:00
|
|
|
// else blocks not same type, or not siblings. Delete everything except
|
|
|
|
// table elements.
|
|
|
|
*aHandled = PR_TRUE;
|
|
|
|
nsCOMPtr<nsIEnumerator> enumerator;
|
2000-09-14 15:45:01 +04:00
|
|
|
res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
|
2000-08-28 09:11:49 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!enumerator) return NS_ERROR_UNEXPECTED;
|
|
|
|
|
|
|
|
for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next())
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupports> currentItem;
|
|
|
|
res = enumerator->CurrentItem(getter_AddRefs(currentItem));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!currentItem) return NS_ERROR_UNEXPECTED;
|
|
|
|
|
|
|
|
// build a list of nodes in the range
|
|
|
|
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
|
|
|
nsTrivialFunctor functor;
|
|
|
|
nsDOMSubtreeIterator iter;
|
|
|
|
res = iter.Init(range);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = iter.MakeList(functor, address_of(arrayOfNodes));
|
2000-08-28 09:11:49 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// now that we have the list, delete non table elements
|
|
|
|
PRUint32 listCount;
|
|
|
|
PRUint32 j;
|
|
|
|
nsCOMPtr<nsIDOMNode> somenode;
|
|
|
|
nsCOMPtr<nsISupports> isupports;
|
|
|
|
|
|
|
|
arrayOfNodes->Count(&listCount);
|
|
|
|
for (j = 0; j < listCount; j++)
|
|
|
|
{
|
|
|
|
isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
|
|
|
|
somenode = do_QueryInterface(isupports);
|
|
|
|
res = DeleteNonTableElements(somenode);
|
|
|
|
arrayOfNodes->RemoveElementAt(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check endopints for possible text deletion.
|
|
|
|
// we can assume that if text node is found, we can
|
|
|
|
// delete to end or to begining as appropriate,
|
|
|
|
// since the case where both sel endpoints in same
|
|
|
|
// text node was already handled (we wouldn't be here)
|
2001-01-28 23:13:07 +03:00
|
|
|
if ( mHTMLEditor->IsTextNode(startNode) )
|
2000-08-28 09:11:49 +04:00
|
|
|
{
|
|
|
|
// delete to last character
|
|
|
|
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
|
|
|
PRUint32 len;
|
|
|
|
nodeAsText = do_QueryInterface(startNode);
|
|
|
|
nodeAsText->GetLength(&len);
|
2000-11-17 03:25:31 +03:00
|
|
|
if (len > (PRUint32)startOffset)
|
2000-08-28 09:11:49 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteText(nodeAsText,startOffset,len-startOffset);
|
2000-08-28 09:11:49 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
if ( mHTMLEditor->IsTextNode(endNode) )
|
2000-08-28 09:11:49 +04:00
|
|
|
{
|
|
|
|
// delete to first character
|
|
|
|
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
|
|
|
nodeAsText = do_QueryInterface(endNode);
|
|
|
|
if (endOffset)
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteText(nodeAsText,0,endOffset);
|
2000-08-28 09:11:49 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (aAction == nsIEditor::eNext)
|
|
|
|
{
|
|
|
|
res = aSelection->Collapse(endNode,0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
res = aSelection->Collapse(startNode,startOffset);
|
|
|
|
}
|
1999-04-26 18:08:52 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-04-12 16:01:32 +04:00
|
|
|
|
1999-04-26 18:08:52 +04:00
|
|
|
return res;
|
|
|
|
}
|
1999-04-12 16:01:32 +04:00
|
|
|
|
2000-08-28 09:11:49 +04:00
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::DeleteNonTableElements(nsIDOMNode *aNode)
|
|
|
|
{
|
|
|
|
if (!aNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
if (nsHTMLEditUtils::IsTableElement(aNode) && !nsHTMLEditUtils::IsTable(aNode))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNodeList> children;
|
|
|
|
aNode->GetChildNodes(getter_AddRefs(children));
|
|
|
|
if (children)
|
|
|
|
{
|
|
|
|
PRUint32 len;
|
|
|
|
children->GetLength(&len);
|
|
|
|
if (!len) return NS_OK;
|
|
|
|
PRInt32 j;
|
|
|
|
for (j=len-1; j>=0; j--)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
children->Item(j,getter_AddRefs(node));
|
|
|
|
res = DeleteNonTableElements(node);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(aNode);
|
2000-08-28 09:11:49 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
1999-06-03 10:01:08 +04:00
|
|
|
|
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::WillMakeList(nsISelection *aSelection,
|
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
|
|
|
const nsString *aListType,
|
2000-09-14 09:59:19 +04:00
|
|
|
PRBool aEntireList,
|
1999-10-06 23:34:09 +04:00
|
|
|
PRBool *aCancel,
|
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
|
|
|
PRBool *aHandled,
|
|
|
|
const nsString *aItemType)
|
1999-06-03 10:01:08 +04:00
|
|
|
{
|
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 (!aSelection || !aListType || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
1999-09-06 23:51:59 +04:00
|
|
|
|
|
|
|
nsresult res = WillInsert(aSelection, aCancel);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
1999-06-03 10:01:08 +04:00
|
|
|
// initialize out param
|
1999-09-06 23:51:59 +04:00
|
|
|
// we want to ignore result of WillInsert()
|
1999-08-10 01:50:02 +04:00
|
|
|
*aCancel = PR_FALSE;
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_FALSE;
|
1999-09-06 23:51:59 +04:00
|
|
|
|
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
|
|
|
// deduce what tag to use for list items
|
|
|
|
nsAutoString itemType;
|
|
|
|
if (aItemType)
|
|
|
|
itemType = *aItemType;
|
|
|
|
else if (aListType->EqualsWithConversion("dl"))
|
|
|
|
itemType.AssignWithConversion("dd");
|
|
|
|
else
|
|
|
|
itemType.AssignWithConversion("li");
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2000-08-26 08:03:50 +04:00
|
|
|
// convert the selection ranges into "promoted" selection ranges:
|
|
|
|
// this basically just expands the range to include the immediate
|
|
|
|
// block parent, and then further expands to include any ancestors
|
|
|
|
// whose children are all in the range
|
|
|
|
|
|
|
|
*aHandled = PR_TRUE;
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
|
2000-08-26 08:03:50 +04:00
|
|
|
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetListActionNodes(address_of(arrayOfNodes), aEntireList);
|
1999-08-10 01:50:02 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-08-26 08:03:50 +04:00
|
|
|
|
|
|
|
PRUint32 listCount;
|
|
|
|
arrayOfNodes->Count(&listCount);
|
|
|
|
|
2000-08-28 12:40:22 +04:00
|
|
|
// check if al our nodes are <br>s
|
|
|
|
PRBool bOnlyBreaks = PR_TRUE;
|
|
|
|
PRInt32 j;
|
|
|
|
for (j=0; j<(PRInt32)listCount; j++)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(j));
|
|
|
|
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
|
|
|
|
// if curNode is not a Break, we're done
|
|
|
|
if (!nsHTMLEditUtils::IsBreak(curNode))
|
|
|
|
{
|
|
|
|
bOnlyBreaks = PR_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if no nodes, we make empty list. Ditto if the user tried to make a list of some # of breaks.
|
|
|
|
if (!listCount || bOnlyBreaks)
|
2000-02-25 07:39:30 +03:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> parent, theList, theListItem;
|
|
|
|
PRInt32 offset;
|
2000-08-28 12:40:22 +04:00
|
|
|
|
|
|
|
// if only breaks, delete them
|
|
|
|
if (bOnlyBreaks)
|
|
|
|
{
|
|
|
|
for (j=0; j<(PRInt32)listCount; j++)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(j));
|
|
|
|
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(curNode);
|
2000-08-28 12:40:22 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
2000-02-25 07:39:30 +03:00
|
|
|
|
|
|
|
// get selection location
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(parent), &offset);
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// make sure we can put a list here
|
2000-12-09 07:46:08 +03:00
|
|
|
res = SplitAsNeeded(aListType, address_of(parent), &offset);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateNode(*aListType, parent, offset, getter_AddRefs(theList));
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateNode(itemType, theList, 0, getter_AddRefs(theListItem));
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// put selection in new list item
|
|
|
|
res = aSelection->Collapse(theListItem,0);
|
2000-08-26 08:03:50 +04:00
|
|
|
selectionResetter.Abort(); // to prevent selection reseter from overriding us.
|
2000-04-24 15:51:12 +04:00
|
|
|
*aHandled = PR_TRUE;
|
2000-02-25 07:39:30 +03:00
|
|
|
return res;
|
|
|
|
}
|
1999-08-10 01:50:02 +04:00
|
|
|
|
1999-06-25 13:33:02 +04:00
|
|
|
// if there is only one node in the array, and it is a list, div, or blockquote,
|
|
|
|
// then look inside of it until we find what we want to make a list out of.
|
|
|
|
if (listCount == 1)
|
|
|
|
{
|
1999-07-01 17:42:03 +04:00
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
|
|
|
|
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
|
1999-06-25 13:33:02 +04:00
|
|
|
|
2000-01-26 03:57:37 +03:00
|
|
|
while (nsHTMLEditUtils::IsDiv(curNode)
|
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
|
|
|
|| nsHTMLEditUtils::IsList(curNode)
|
2000-01-26 03:57:37 +03:00
|
|
|
|| nsHTMLEditUtils::IsBlockquote(curNode))
|
1999-06-25 13:33:02 +04:00
|
|
|
{
|
2000-02-25 07:39:30 +03:00
|
|
|
// dive as long as there is only one child, and it is a list, div, blockquote
|
1999-06-25 14:36:54 +04:00
|
|
|
PRUint32 numChildren;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CountEditableChildren(curNode, numChildren);
|
1999-06-25 13:33:02 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
if (numChildren == 1)
|
|
|
|
{
|
|
|
|
// keep diving
|
|
|
|
nsCOMPtr <nsIDOMNode> tmpNode = nsEditor::GetChildAt(curNode, 0);
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsDiv(tmpNode)
|
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
|
|
|
|| nsHTMLEditUtils::IsList(tmpNode)
|
2000-01-26 03:57:37 +03:00
|
|
|
|| nsHTMLEditUtils::IsBlockquote(tmpNode))
|
1999-07-01 17:42:03 +04:00
|
|
|
{
|
1999-08-18 12:13:06 +04:00
|
|
|
// check editablility XXX floppy moose
|
1999-07-01 17:42:03 +04:00
|
|
|
curNode = tmpNode;
|
|
|
|
}
|
|
|
|
else break;
|
1999-06-25 13:33:02 +04:00
|
|
|
}
|
1999-07-01 17:42:03 +04:00
|
|
|
else break;
|
1999-06-25 13:33:02 +04:00
|
|
|
}
|
|
|
|
// we've found innermost list/blockquote/div:
|
|
|
|
// replace the one node in the array with this node
|
1999-07-01 17:42:03 +04:00
|
|
|
isupports = do_QueryInterface(curNode);
|
|
|
|
arrayOfNodes->ReplaceElementAt(isupports, 0);
|
1999-06-25 13:33:02 +04:00
|
|
|
}
|
|
|
|
|
1999-06-16 09:02:43 +04:00
|
|
|
// Next we detect all the transitions in the array, where a transition
|
|
|
|
// means that adjacent nodes in the array don't have the same parent.
|
|
|
|
|
|
|
|
nsVoidArray transitionList;
|
1999-07-01 17:42:03 +04:00
|
|
|
res = MakeTransitionList(arrayOfNodes, &transitionList);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
1999-06-25 13:33:02 +04:00
|
|
|
// Ok, now go through all the nodes and put then in the list,
|
1999-06-16 09:02:43 +04:00
|
|
|
// or whatever is approriate. Wohoo!
|
1999-07-01 17:42:03 +04:00
|
|
|
|
|
|
|
arrayOfNodes->Count(&listCount);
|
1999-06-16 09:02:43 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> curParent;
|
|
|
|
nsCOMPtr<nsIDOMNode> curList;
|
1999-08-11 01:44:10 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> prevListItem;
|
2000-05-03 04:14:28 +04:00
|
|
|
|
|
|
|
PRInt32 i;
|
2000-02-25 07:39:30 +03:00
|
|
|
for (i=0; i<(PRInt32)listCount; i++)
|
|
|
|
{
|
|
|
|
// here's where we actually figure out what to do
|
2000-05-03 04:14:28 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> newBlock;
|
2000-02-25 07:39:30 +03:00
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
|
|
|
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
|
|
|
|
PRInt32 offset;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2000-04-24 15:51:12 +04:00
|
|
|
// if curNode is a Break, delete it, and quit remembering prev list item
|
|
|
|
if (nsHTMLEditUtils::IsBreak(curNode))
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(curNode);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
prevListItem = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// if curNode is an empty inline container, delete it
|
2001-01-28 23:13:07 +03:00
|
|
|
else if (mHTMLEditor->IsInlineNode(curNode) && mHTMLEditor->IsContainer(curNode))
|
2000-04-24 15:51:12 +04:00
|
|
|
{
|
|
|
|
PRBool bEmpty;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->IsEmptyNode(curNode, &bEmpty);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (bEmpty)
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(curNode);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-05-03 04:14:28 +04:00
|
|
|
if (nsHTMLEditUtils::IsList(curNode))
|
1999-06-16 09:02:43 +04:00
|
|
|
{
|
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 existingListStr;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetTagString(curNode, existingListStr);
|
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
|
|
|
existingListStr.ToLowerCase();
|
2000-05-03 04:14:28 +04:00
|
|
|
// do we have a curList already?
|
|
|
|
if (curList && !nsHTMLEditUtils::IsDescendantOf(curNode, curList))
|
1999-06-16 09:02:43 +04:00
|
|
|
{
|
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
|
|
|
// move all of our children into curList.
|
2000-05-03 04:14:28 +04:00
|
|
|
// cheezy way to do it: move whole list and then
|
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
|
|
|
// RemoveContainer() on the list.
|
|
|
|
// ConvertListType first: that routine
|
|
|
|
// handles converting the list item types, if needed
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->MoveNode(curNode, curList, -1);
|
2000-05-03 04:14:28 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = ConvertListType(curNode, address_of(newBlock), *aListType, itemType);
|
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;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->RemoveContainer(newBlock);
|
2000-05-03 04:14:28 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-08-11 01:44:10 +04:00
|
|
|
}
|
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
|
|
|
else
|
1999-06-25 13:33:02 +04:00
|
|
|
{
|
2000-05-03 04:14:28 +04:00
|
|
|
// replace list with new list type
|
2000-12-09 07:46:08 +03:00
|
|
|
res = ConvertListType(curNode, address_of(newBlock), *aListType, itemType);
|
2000-05-03 04:14:28 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
curList = newBlock;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nsHTMLEditUtils::IsListItem(curNode))
|
|
|
|
{
|
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 existingListStr;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetTagString(curParent, existingListStr);
|
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
|
|
|
existingListStr.ToLowerCase();
|
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 ( existingListStr != *aListType )
|
2000-05-03 04:14:28 +04:00
|
|
|
{
|
|
|
|
// list item is in wrong type of list.
|
|
|
|
// if we dont have a curList, split the old list
|
|
|
|
// and make a new list of correct type.
|
|
|
|
if (!curList || nsHTMLEditUtils::IsDescendantOf(curNode, curList))
|
1999-08-11 01:44:10 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SplitNode(curParent, offset, getter_AddRefs(newBlock));
|
2000-05-03 04:14:28 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
nsCOMPtr<nsIDOMNode> p;
|
|
|
|
PRInt32 o;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(curParent, address_of(p), &o);
|
2000-05-03 04:14:28 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateNode(*aListType, p, o, getter_AddRefs(curList));
|
1999-08-11 01:44:10 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
2000-05-03 04:14:28 +04:00
|
|
|
// move list item to new list
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->MoveNode(curNode, curList, -1);
|
2000-05-03 04:14:28 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
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
|
|
|
// convert list item type if needed
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!mHTMLEditor->NodeIsType(curNode,itemType))
|
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
|
|
|
res = mHTMLEditor->ReplaceContainer(curNode, address_of(newBlock), itemType);
|
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-05-03 04:14:28 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// item is in right type of list. But we might still have to move it.
|
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
|
|
|
// and we might need to convert list item types.
|
2000-05-03 04:14:28 +04:00
|
|
|
if (!curList)
|
|
|
|
curList = curParent;
|
1999-08-11 01:44:10 +04:00
|
|
|
else
|
|
|
|
{
|
2000-05-03 04:14:28 +04:00
|
|
|
if (curParent != curList)
|
|
|
|
{
|
|
|
|
// move list item to new list
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->MoveNode(curNode, curList, -1);
|
2000-05-03 04:14:28 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
1999-08-11 01:44:10 +04:00
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!mHTMLEditor->NodeIsType(curNode,itemType))
|
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
|
|
|
res = mHTMLEditor->ReplaceContainer(curNode, address_of(newBlock), itemType);
|
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;
|
|
|
|
}
|
1999-06-25 13:33:02 +04:00
|
|
|
}
|
2000-05-03 04:14:28 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2000-02-25 07:39:30 +03:00
|
|
|
// need to make a list to put things in if we haven't already,
|
|
|
|
// or if this node doesn't go in list we used earlier.
|
2000-05-03 04:14:28 +04:00
|
|
|
if (!curList) // || transitionList[i])
|
2000-02-25 07:39:30 +03:00
|
|
|
{
|
2000-12-09 07:46:08 +03:00
|
|
|
res = SplitAsNeeded(aListType, address_of(curParent), &offset);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateNode(*aListType, curParent, offset, getter_AddRefs(curList));
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// curList is now the correct thing to put curNode in
|
|
|
|
prevListItem = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if curNode isn't a list item, we must wrap it in one
|
|
|
|
nsCOMPtr<nsIDOMNode> listItem;
|
|
|
|
if (!nsHTMLEditUtils::IsListItem(curNode))
|
|
|
|
{
|
|
|
|
if (nsEditor::IsInlineNode(curNode) && prevListItem)
|
1999-08-11 01:44:10 +04:00
|
|
|
{
|
2000-02-25 07:39:30 +03:00
|
|
|
// this is a continuation of some inline nodes that belong together in
|
|
|
|
// the same list item. use prevListItem
|
|
|
|
PRUint32 listItemLen;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetLengthOfDOMNode(prevListItem, listItemLen);
|
1999-08-11 01:44:10 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->MoveNode(curNode, prevListItem, listItemLen);
|
1999-08-11 01:44:10 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
2000-02-25 07:39:30 +03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// don't wrap li around a paragraph. instead replace paragraph with li
|
|
|
|
if (nsHTMLEditUtils::IsParagraph(curNode))
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->ReplaceContainer(curNode, address_of(listItem), itemType);
|
2000-02-25 07:39:30 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->InsertContainerAbove(curNode, address_of(listItem), itemType);
|
2000-02-25 07:39:30 +03:00
|
|
|
}
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (nsEditor::IsInlineNode(curNode))
|
|
|
|
prevListItem = listItem;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
listItem = curNode;
|
1999-06-16 09:02:43 +04:00
|
|
|
}
|
2000-02-25 07:39:30 +03:00
|
|
|
|
|
|
|
if (listItem) // if we made a new list item, deal with it
|
|
|
|
{
|
|
|
|
// tuck the listItem into the end of the active list
|
|
|
|
PRUint32 listLen;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetLengthOfDOMNode(curList, listLen);
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->MoveNode(listItem, curList, listLen);
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
1999-06-16 09:02:43 +04:00
|
|
|
|
1999-06-03 10:01:08 +04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-09-06 23:51:59 +04:00
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::WillRemoveList(nsISelection *aSelection,
|
1999-10-06 23:34:09 +04:00
|
|
|
PRBool aOrdered,
|
|
|
|
PRBool *aCancel,
|
|
|
|
PRBool *aHandled)
|
1999-09-06 23:51:59 +04:00
|
|
|
{
|
1999-10-06 23:34:09 +04:00
|
|
|
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
1999-09-06 23:51:59 +04:00
|
|
|
// initialize out param
|
1999-10-06 23:34:09 +04:00
|
|
|
*aCancel = PR_FALSE;
|
|
|
|
*aHandled = PR_TRUE;
|
1999-09-06 23:51:59 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
|
1999-09-06 23:51:59 +04:00
|
|
|
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfRanges;
|
2000-12-09 07:46:08 +03:00
|
|
|
nsresult res = GetPromotedRanges(aSelection, address_of(arrayOfRanges), kMakeList);
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// use these ranges to contruct a list of nodes to act on.
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetNodesForOperation(arrayOfRanges, address_of(arrayOfNodes), kMakeList);
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// Remove all non-editable nodes. Leave them be.
|
|
|
|
|
|
|
|
PRUint32 listCount;
|
|
|
|
PRInt32 i;
|
|
|
|
arrayOfNodes->Count(&listCount);
|
|
|
|
for (i=listCount-1; i>=0; i--)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
|
|
|
nsCOMPtr<nsIDOMNode> testNode( do_QueryInterface(isupports ) );
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!mHTMLEditor->IsEditable(testNode))
|
1999-09-06 23:51:59 +04:00
|
|
|
{
|
|
|
|
arrayOfNodes->RemoveElementAt(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only act on lists or list items in the array
|
|
|
|
nsCOMPtr<nsIDOMNode> curParent;
|
1999-09-11 04:20:59 +04:00
|
|
|
for (i=0; i<(PRInt32)listCount; i++)
|
1999-09-06 23:51:59 +04:00
|
|
|
{
|
|
|
|
// here's where we actually figure out what to do
|
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
|
|
|
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
|
|
|
|
PRInt32 offset;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsListItem(curNode)) // unlist this listitem
|
1999-09-06 23:51:59 +04:00
|
|
|
{
|
|
|
|
PRBool bOutOfList;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
res = PopListItem(curNode, &bOutOfList);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
} while (!bOutOfList); // keep popping it out until it's not in a list anymore
|
|
|
|
}
|
2000-01-26 03:57:37 +03:00
|
|
|
else if (nsHTMLEditUtils::IsList(curNode)) // node is a list, move list items out
|
1999-09-06 23:51:59 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> child;
|
|
|
|
curNode->GetLastChild(getter_AddRefs(child));
|
|
|
|
|
|
|
|
while (child)
|
|
|
|
{
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsListItem(child))
|
1999-09-06 23:51:59 +04:00
|
|
|
{
|
|
|
|
PRBool bOutOfList;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
res = PopListItem(child, &bOutOfList);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
} while (!bOutOfList); // keep popping it out until it's not in a list anymore
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// delete any non- list items for now
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(child);
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
curNode->GetLastChild(getter_AddRefs(child));
|
|
|
|
}
|
|
|
|
// delete the now-empty list
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(curNode);
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::WillMakeDefListItem(nsISelection *aSelection,
|
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
|
|
|
const nsString *aItemType,
|
2000-09-14 09:59:19 +04:00
|
|
|
PRBool aEntireList,
|
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
|
|
|
PRBool *aCancel,
|
|
|
|
PRBool *aHandled)
|
|
|
|
{
|
|
|
|
// for now we let WillMakeList handle this
|
|
|
|
nsAutoString listType;
|
|
|
|
listType.AssignWithConversion("dl");
|
2000-09-14 09:59:19 +04:00
|
|
|
return WillMakeList(aSelection, &listType, aEntireList, aCancel, aHandled, aItemType);
|
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
|
|
|
}
|
|
|
|
|
1999-08-10 01:50:02 +04:00
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::WillMakeBasicBlock(nsISelection *aSelection,
|
1999-10-06 23:34:09 +04:00
|
|
|
const nsString *aBlockType,
|
|
|
|
PRBool *aCancel,
|
|
|
|
PRBool *aHandled)
|
1999-08-10 01:50:02 +04:00
|
|
|
{
|
1999-10-06 23:34:09 +04:00
|
|
|
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
1999-08-10 01:50:02 +04:00
|
|
|
// initialize out param
|
1999-08-18 12:13:06 +04:00
|
|
|
*aCancel = PR_FALSE;
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_FALSE;
|
1999-08-10 01:50:02 +04:00
|
|
|
|
2000-02-25 07:39:30 +03:00
|
|
|
nsresult res = WillInsert(aSelection, aCancel);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// initialize out param
|
|
|
|
// we want to ignore result of WillInsert()
|
|
|
|
*aCancel = PR_FALSE;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
|
|
|
|
nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_TRUE;
|
1999-08-10 01:50:02 +04:00
|
|
|
|
1999-08-18 12:13:06 +04:00
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfRanges;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetPromotedRanges(aSelection, address_of(arrayOfRanges), kMakeBasicBlock);
|
1999-08-18 12:13:06 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// use these ranges to contruct a list of nodes to act on.
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetNodesForOperation(arrayOfRanges, address_of(arrayOfNodes), kMakeBasicBlock);
|
1999-08-18 12:13:06 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2000-08-26 08:03:50 +04:00
|
|
|
// if no nodes, we make empty block.
|
|
|
|
PRUint32 listCount;
|
|
|
|
arrayOfNodes->Count(&listCount);
|
|
|
|
if (!listCount)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> parent, theBlock;
|
|
|
|
PRInt32 offset;
|
|
|
|
|
|
|
|
// get selection location
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(parent), &offset);
|
2000-08-26 08:03:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// make sure we can put a block here
|
2000-12-09 07:46:08 +03:00
|
|
|
res = SplitAsNeeded(aBlockType, address_of(parent), &offset);
|
2000-08-26 08:03:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateNode(*aBlockType, parent, offset, getter_AddRefs(theBlock));
|
2000-08-26 08:03:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// put selection in new block
|
|
|
|
res = aSelection->Collapse(theBlock,0);
|
|
|
|
selectionResetter.Abort(); // to prevent selection reseter from overriding us.
|
|
|
|
*aHandled = PR_TRUE;
|
|
|
|
return res;
|
|
|
|
}
|
2000-04-24 15:51:12 +04:00
|
|
|
else
|
2000-08-26 08:03:50 +04:00
|
|
|
{
|
|
|
|
// Ok, now go through all the nodes and make the right kind of blocks,
|
|
|
|
// or whatever is approriate. Wohoo!
|
|
|
|
// Note: blockquote is handled a little differently
|
|
|
|
if (aBlockType->EqualsWithConversion("blockquote"))
|
|
|
|
res = MakeBlockquote(arrayOfNodes);
|
|
|
|
else
|
|
|
|
res = ApplyBlockStyle(arrayOfNodes, aBlockType);
|
|
|
|
return res;
|
|
|
|
}
|
1999-08-18 12:13:06 +04:00
|
|
|
return res;
|
1999-08-10 01:50:02 +04:00
|
|
|
}
|
|
|
|
|
2000-03-31 03:39:26 +04:00
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::DidMakeBasicBlock(nsISelection *aSelection,
|
2000-03-31 02:57:19 +04:00
|
|
|
nsRulesInfo *aInfo, nsresult aResult)
|
|
|
|
{
|
|
|
|
if (!aSelection) return NS_ERROR_NULL_POINTER;
|
|
|
|
// check for empty block. if so, put a moz br in it.
|
|
|
|
PRBool isCollapsed;
|
|
|
|
nsresult res = aSelection->GetIsCollapsed(&isCollapsed);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!isCollapsed) return NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
PRInt32 offset;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetStartNodeAndOffset(aSelection, address_of(parent), &offset);
|
2000-03-31 02:57:19 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = InsertMozBRIfNeeded(parent);
|
|
|
|
return res;
|
|
|
|
}
|
1999-08-10 01:50:02 +04:00
|
|
|
|
1999-06-03 10:01:08 +04:00
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::WillIndent(nsISelection *aSelection, PRBool *aCancel, PRBool * aHandled)
|
1999-06-03 10:01:08 +04:00
|
|
|
{
|
1999-10-06 23:34:09 +04:00
|
|
|
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
1999-09-06 23:51:59 +04:00
|
|
|
|
|
|
|
nsresult res = WillInsert(aSelection, aCancel);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
1999-06-03 10:01:08 +04:00
|
|
|
// initialize out param
|
1999-09-06 23:51:59 +04:00
|
|
|
// we want to ignore result of WillInsert()
|
1999-10-06 23:34:09 +04:00
|
|
|
*aCancel = PR_FALSE;
|
|
|
|
*aHandled = PR_TRUE;
|
1999-09-06 23:51:59 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
|
1999-06-16 09:02:43 +04:00
|
|
|
|
1999-07-01 17:42:03 +04:00
|
|
|
// convert the selection ranges into "promoted" selection ranges:
|
|
|
|
// this basically just expands the range to include the immediate
|
|
|
|
// block parent, and then further expands to include any ancestors
|
|
|
|
// whose children are all in the range
|
1999-06-16 09:02:43 +04:00
|
|
|
|
1999-07-01 17:42:03 +04:00
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfRanges;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetPromotedRanges(aSelection, address_of(arrayOfRanges), kIndent);
|
1999-06-16 09:02:43 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
1999-07-01 17:42:03 +04:00
|
|
|
// use these ranges to contruct a list of nodes to act on.
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetNodesForOperation(arrayOfRanges, address_of(arrayOfNodes), kIndent);
|
1999-07-01 17:42:03 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2000-08-26 08:03:50 +04:00
|
|
|
// if no nodes, we make empty block.
|
|
|
|
PRUint32 listCount;
|
|
|
|
arrayOfNodes->Count(&listCount);
|
|
|
|
if (!listCount)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> parent, theBlock;
|
|
|
|
PRInt32 offset;
|
|
|
|
nsAutoString quoteType; quoteType.AssignWithConversion("blockquote");
|
|
|
|
|
|
|
|
// get selection location
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(parent), &offset);
|
2000-08-26 08:03:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// make sure we can put a block here
|
2000-12-09 07:46:08 +03:00
|
|
|
res = SplitAsNeeded("eType, address_of(parent), &offset);
|
2000-08-26 08:03:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateNode(quoteType, parent, offset, getter_AddRefs(theBlock));
|
2000-08-26 08:03:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// put selection in new block
|
|
|
|
res = aSelection->Collapse(theBlock,0);
|
|
|
|
selectionResetter.Abort(); // to prevent selection reseter from overriding us.
|
|
|
|
*aHandled = PR_TRUE;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
1999-06-16 09:02:43 +04:00
|
|
|
// Next we detect all the transitions in the array, where a transition
|
|
|
|
// means that adjacent nodes in the array don't have the same parent.
|
|
|
|
|
|
|
|
nsVoidArray transitionList;
|
1999-07-01 17:42:03 +04:00
|
|
|
res = MakeTransitionList(arrayOfNodes, &transitionList);
|
|
|
|
if (NS_FAILED(res)) return res;
|
1999-06-16 09:02:43 +04:00
|
|
|
|
1999-07-01 17:42:03 +04:00
|
|
|
// Ok, now go through all the nodes and put them in a blockquote,
|
1999-06-16 09:02:43 +04:00
|
|
|
// or whatever is appropriate. Wohoo!
|
1999-07-01 17:42:03 +04:00
|
|
|
|
|
|
|
PRInt32 i;
|
1999-06-16 09:02:43 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> curParent;
|
|
|
|
nsCOMPtr<nsIDOMNode> curQuote;
|
1999-08-10 01:50:02 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> curList;
|
1999-09-11 04:20:59 +04:00
|
|
|
for (i=0; i<(PRInt32)listCount; i++)
|
1999-06-16 09:02:43 +04:00
|
|
|
{
|
|
|
|
// here's where we actually figure out what to do
|
1999-07-01 17:42:03 +04:00
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
|
|
|
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
|
1999-06-16 09:02:43 +04:00
|
|
|
PRInt32 offset;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
|
1999-06-16 09:02:43 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
1999-08-10 01:50:02 +04:00
|
|
|
// some logic for putting list items into nested lists...
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsList(curParent))
|
1999-06-16 09:02:43 +04:00
|
|
|
{
|
1999-08-10 01:50:02 +04:00
|
|
|
if (!curList || transitionList[i])
|
1999-07-20 02:49:21 +04:00
|
|
|
{
|
1999-08-24 12:56:51 +04:00
|
|
|
nsAutoString listTag;
|
|
|
|
nsEditor::GetTagString(curParent,listTag);
|
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
|
|
|
listTag.ToLowerCase();
|
1999-08-24 12:56:51 +04:00
|
|
|
// create a new nested list of correct type
|
2000-12-09 07:46:08 +03:00
|
|
|
res = SplitAsNeeded(&listTag, address_of(curParent), &offset);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateNode(listTag, curParent, offset, getter_AddRefs(curList));
|
1999-08-24 12:56:51 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// curList is now the correct thing to put curNode in
|
1999-07-20 02:49:21 +04:00
|
|
|
}
|
1999-08-10 01:50:02 +04:00
|
|
|
// tuck the node into the end of the active list
|
|
|
|
PRUint32 listLen;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetLengthOfDOMNode(curList, listLen);
|
1999-08-10 01:50:02 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->MoveNode(curNode, curList, listLen);
|
1999-08-10 01:50:02 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
else // not a list item, use blockquote
|
|
|
|
{
|
|
|
|
// need to make a blockquote to put things in if we haven't already,
|
|
|
|
// or if this node doesn't go in blockquote we used earlier.
|
2000-08-26 08:03:50 +04:00
|
|
|
if (!curQuote) // || transitionList[i])
|
1999-07-20 02:49:21 +04:00
|
|
|
{
|
2000-04-18 11:52:02 +04:00
|
|
|
nsAutoString quoteType; quoteType.AssignWithConversion("blockquote");
|
2000-12-09 07:46:08 +03:00
|
|
|
res = SplitAsNeeded("eType, address_of(curParent), &offset);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateNode(quoteType, curParent, offset, getter_AddRefs(curQuote));
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-07-22 02:06:48 +04:00
|
|
|
|
|
|
|
/* !!!!!!!!!!!!!!! TURNED OFF PER BUG 33213 !!!!!!!!!!!!!!!!!!!!
|
2000-04-24 15:51:12 +04:00
|
|
|
// set style to not have unwanted vertical margins
|
|
|
|
nsCOMPtr<nsIDOMElement> quoteElem = do_QueryInterface(curQuote);
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SetAttribute(quoteElem, NS_ConvertASCIItoUCS2("style"), NS_ConvertASCIItoUCS2("margin: 0 0 0 40px;"));
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-07-22 02:06:48 +04:00
|
|
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
|
|
|
|
|
2000-04-24 15:51:12 +04:00
|
|
|
// curQuote is now the correct thing to put curNode in
|
1999-07-20 02:49:21 +04:00
|
|
|
}
|
1999-06-16 09:02:43 +04:00
|
|
|
|
1999-08-10 01:50:02 +04:00
|
|
|
// tuck the node into the end of the active blockquote
|
|
|
|
PRUint32 quoteLen;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetLengthOfDOMNode(curQuote, quoteLen);
|
1999-08-10 01:50:02 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->MoveNode(curNode, curQuote, quoteLen);
|
1999-08-10 01:50:02 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
1999-06-16 09:02:43 +04:00
|
|
|
}
|
1999-06-03 10:01:08 +04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled)
|
1999-06-03 10:01:08 +04:00
|
|
|
{
|
1999-10-06 23:34:09 +04:00
|
|
|
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
1999-06-03 10:01:08 +04:00
|
|
|
// initialize out param
|
1999-10-06 23:34:09 +04:00
|
|
|
*aCancel = PR_FALSE;
|
|
|
|
*aHandled = PR_TRUE;
|
1999-06-03 10:01:08 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
|
1999-06-03 10:01:08 +04:00
|
|
|
nsresult res = NS_OK;
|
|
|
|
|
1999-07-01 17:42:03 +04:00
|
|
|
// convert the selection ranges into "promoted" selection ranges:
|
|
|
|
// this basically just expands the range to include the immediate
|
|
|
|
// block parent, and then further expands to include any ancestors
|
|
|
|
// whose children are all in the range
|
1999-06-16 09:02:43 +04:00
|
|
|
|
1999-07-01 17:42:03 +04:00
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfRanges;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetPromotedRanges(aSelection, address_of(arrayOfRanges), kOutdent);
|
1999-06-16 09:02:43 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
1999-07-01 17:42:03 +04:00
|
|
|
// use these ranges to contruct a list of nodes to act on.
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetNodesForOperation(arrayOfRanges, address_of(arrayOfNodes), kOutdent);
|
1999-07-01 17:42:03 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
1999-06-16 09:02:43 +04:00
|
|
|
// Next we detect all the transitions in the array, where a transition
|
|
|
|
// means that adjacent nodes in the array don't have the same parent.
|
|
|
|
|
|
|
|
nsVoidArray transitionList;
|
1999-07-01 17:42:03 +04:00
|
|
|
res = MakeTransitionList(arrayOfNodes, &transitionList);
|
|
|
|
if (NS_FAILED(res)) return res;
|
1999-06-16 09:02:43 +04:00
|
|
|
|
1999-07-01 17:42:03 +04:00
|
|
|
// Ok, now go through all the nodes and remove a level of blockquoting,
|
1999-06-16 09:02:43 +04:00
|
|
|
// or whatever is appropriate. Wohoo!
|
1999-07-01 17:42:03 +04:00
|
|
|
|
|
|
|
PRUint32 listCount;
|
|
|
|
PRInt32 i;
|
|
|
|
arrayOfNodes->Count(&listCount);
|
1999-06-16 09:02:43 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> curParent;
|
1999-09-11 04:20:59 +04:00
|
|
|
for (i=0; i<(PRInt32)listCount; i++)
|
1999-06-16 09:02:43 +04:00
|
|
|
{
|
|
|
|
// here's where we actually figure out what to do
|
1999-07-01 17:42:03 +04:00
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
|
|
|
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
|
1999-06-16 09:02:43 +04:00
|
|
|
PRInt32 offset;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
|
1999-06-16 09:02:43 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsList(curParent)) // move node out of list
|
1999-08-24 12:56:51 +04:00
|
|
|
{
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsList(curNode)) // just unwrap this sublist
|
1999-08-24 12:56:51 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->RemoveContainer(curNode);
|
1999-08-24 12:56:51 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
else // we are moving a list item, but not whole list
|
|
|
|
{
|
1999-09-06 23:51:59 +04:00
|
|
|
PRBool bOutOfList;
|
|
|
|
res = PopListItem(curNode, &bOutOfList);
|
1999-08-24 12:56:51 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
2000-01-26 03:57:37 +03:00
|
|
|
else if (nsHTMLEditUtils::IsList(curNode)) // node is a list, but parent is non-list: move list items out
|
1999-08-24 12:56:51 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> child;
|
|
|
|
curNode->GetLastChild(getter_AddRefs(child));
|
|
|
|
while (child)
|
|
|
|
{
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsListItem(child))
|
1999-08-24 12:56:51 +04:00
|
|
|
{
|
1999-09-06 23:51:59 +04:00
|
|
|
PRBool bOutOfList;
|
|
|
|
res = PopListItem(child, &bOutOfList);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// delete any non- list items for now
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(child);
|
1999-08-24 12:56:51 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
curNode->GetLastChild(getter_AddRefs(child));
|
|
|
|
}
|
1999-09-06 23:51:59 +04:00
|
|
|
// delete the now-empty list
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(curNode);
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-08-24 12:56:51 +04:00
|
|
|
}
|
|
|
|
else if (transitionList[i]) // not list related - look for enclosing blockquotes and remove
|
1999-06-16 09:02:43 +04:00
|
|
|
{
|
1999-06-25 13:33:02 +04:00
|
|
|
// look for a blockquote somewhere above us and remove it.
|
1999-06-16 09:02:43 +04:00
|
|
|
// this is a hack until i think about outdent for real.
|
|
|
|
nsCOMPtr<nsIDOMNode> n = curNode;
|
|
|
|
nsCOMPtr<nsIDOMNode> tmp;
|
2000-01-26 03:57:37 +03:00
|
|
|
while (!nsHTMLEditUtils::IsBody(n))
|
1999-06-16 09:02:43 +04:00
|
|
|
{
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsBlockquote(n))
|
1999-06-16 09:02:43 +04:00
|
|
|
{
|
2000-04-24 15:51:12 +04:00
|
|
|
res = AddTerminatingBR(n);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
mHTMLEditor->RemoveContainer(n);
|
1999-06-16 09:02:43 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
n->GetParentNode(getter_AddRefs(tmp));
|
|
|
|
n = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-06-03 10:01:08 +04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// ConvertListType: convert list type and list item type.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::ConvertListType(nsIDOMNode *aList,
|
|
|
|
nsCOMPtr<nsIDOMNode> *outList,
|
|
|
|
const nsString& aListType,
|
|
|
|
const nsString& aItemType)
|
|
|
|
{
|
|
|
|
if (!aList || !outList) return NS_ERROR_NULL_POINTER;
|
|
|
|
*outList = aList; // we migvht not need to change the list
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
nsCOMPtr<nsIDOMNode> child, temp;
|
|
|
|
aList->GetFirstChild(getter_AddRefs(child));
|
|
|
|
while (child)
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
if (nsHTMLEditUtils::IsListItem(child) && !mHTMLEditor->NodeIsType(child, aItemType))
|
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
|
|
|
res = mHTMLEditor->ReplaceContainer(child, address_of(temp), aItemType);
|
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;
|
|
|
|
child = temp;
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
else if (nsHTMLEditUtils::IsList(child) && !mHTMLEditor->NodeIsType(child, aListType))
|
2000-09-14 09:59:19 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->ReplaceContainer(child, address_of(temp), aListType);
|
2000-09-14 09:59:19 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
child = temp;
|
|
|
|
}
|
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
|
|
|
child->GetNextSibling(getter_AddRefs(temp));
|
|
|
|
child = temp;
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!mHTMLEditor->NodeIsType(aList, aListType))
|
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
|
|
|
res = mHTMLEditor->ReplaceContainer(aList, outList, aListType);
|
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
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// CreateStyleForInsertText: take care of clearing and setting appropriate
|
|
|
|
// style nodes for text insertion.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::CreateStyleForInsertText(nsISelection *aSelection, nsIDOMDocument *aDoc)
|
2000-03-29 16:53:23 +04:00
|
|
|
{
|
|
|
|
if (!aSelection || !aDoc) return NS_ERROR_NULL_POINTER;
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!mHTMLEditor->mTypeInState) return NS_ERROR_NULL_POINTER;
|
2000-03-29 16:53:23 +04:00
|
|
|
|
2000-05-13 03:43:50 +04:00
|
|
|
PRBool weDidSometing = PR_FALSE;
|
2000-03-29 16:53:23 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
PRInt32 offset;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(node), &offset);
|
2000-03-29 16:53:23 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
PropItem *item = nsnull;
|
|
|
|
|
|
|
|
// process clearing any styles first
|
2001-01-28 23:13:07 +03:00
|
|
|
mHTMLEditor->mTypeInState->TakeClearProperty(&item);
|
2000-03-29 16:53:23 +04:00
|
|
|
while (item)
|
|
|
|
{
|
2000-08-30 08:26:55 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> leftNode, rightNode, secondSplitParent, newSelParent;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SplitStyleAbovePoint(address_of(node), &offset, item->tag, &item->attr, address_of(leftNode), address_of(rightNode));
|
2000-03-29 16:53:23 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-08-30 08:26:55 +04:00
|
|
|
if (rightNode)
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetLeftmostChild(rightNode, getter_AddRefs(secondSplitParent));
|
2000-08-30 08:26:55 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
offset = 0;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SplitStyleAbovePoint(address_of(secondSplitParent), &offset, item->tag, &(item->attr), address_of(leftNode), address_of(rightNode));
|
2000-08-30 08:26:55 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// should be impossible to not get a new leftnode here
|
|
|
|
if (!leftNode) return NS_ERROR_FAILURE;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetLeftmostChild(leftNode, getter_AddRefs(newSelParent));
|
2000-08-30 08:26:55 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// register a rangeStore item that points at the new heirarchy.
|
|
|
|
// This is so we can know where to put the selection after we call
|
|
|
|
// RemoveStyleInside(). RemoveStyleInside() could remove any and all of those nodes,
|
|
|
|
// so I have to use the range tracking system to find the right spot to put selection.
|
|
|
|
nsRangeStore *rangeItem = new nsRangeStore();
|
|
|
|
if (!rangeItem) return NS_ERROR_NULL_POINTER;
|
|
|
|
rangeItem->startNode = newSelParent;
|
|
|
|
rangeItem->endNode = newSelParent;
|
|
|
|
rangeItem->startOffset = 0;
|
|
|
|
rangeItem->endOffset = 0;
|
2001-01-28 23:13:07 +03:00
|
|
|
mHTMLEditor->mRangeUpdater.RegisterRangeItem(rangeItem);
|
2000-08-30 08:26:55 +04:00
|
|
|
// remove the style on this new heirarchy
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->RemoveStyleInside(leftNode, item->tag, &(item->attr));
|
2000-08-30 08:26:55 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// reset our node offset values to the resulting new sel point
|
2001-01-28 23:13:07 +03:00
|
|
|
mHTMLEditor->mRangeUpdater.DropRangeItem(rangeItem);
|
2000-08-30 08:26:55 +04:00
|
|
|
node = rangeItem->startNode;
|
|
|
|
offset = rangeItem->startOffset;
|
|
|
|
delete rangeItem;
|
|
|
|
}
|
2000-03-31 02:57:19 +04:00
|
|
|
// we own item now (TakeClearProperty hands ownership to us)
|
2000-03-30 04:34:26 +04:00
|
|
|
delete item;
|
2001-01-28 23:13:07 +03:00
|
|
|
mHTMLEditor->mTypeInState->TakeClearProperty(&item);
|
2000-05-13 03:43:50 +04:00
|
|
|
weDidSometing = PR_TRUE;
|
2000-03-29 16:53:23 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// then process setting any styles
|
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
|
|
|
PRInt32 relFontSize;
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->mTypeInState->TakeRelativeFontSize(&relFontSize);
|
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;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->mTypeInState->TakeSetProperty(&item);
|
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-03-29 16:53:23 +04:00
|
|
|
|
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 (item || relFontSize) // we have at least one style to add; make a
|
|
|
|
{ // new text node to insert style nodes above.
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->IsTextNode(node))
|
2000-03-29 16:53:23 +04:00
|
|
|
{
|
|
|
|
// if we are in a text node, split it
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SplitNodeDeep(node, node, offset, &offset);
|
2000-03-29 16:53:23 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
nsCOMPtr<nsIDOMNode> tmp;
|
|
|
|
node->GetParentNode(getter_AddRefs(tmp));
|
|
|
|
node = tmp;
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIDOMNode> newNode;
|
|
|
|
nsCOMPtr<nsIDOMText> nodeAsText;
|
2000-04-18 11:52:02 +04:00
|
|
|
res = aDoc->CreateTextNode(nsAutoString(), getter_AddRefs(nodeAsText));
|
2000-03-29 16:53:23 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!nodeAsText) return NS_ERROR_NULL_POINTER;
|
|
|
|
newNode = do_QueryInterface(nodeAsText);
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->InsertNode(newNode, node, offset);
|
2000-03-29 16:53:23 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
node = newNode;
|
|
|
|
offset = 0;
|
2000-05-13 03:43:50 +04:00
|
|
|
weDidSometing = PR_TRUE;
|
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 (relFontSize)
|
|
|
|
{
|
|
|
|
PRInt32 j, dir;
|
|
|
|
// dir indicated bigger versus smaller. 1 = bigger, -1 = smaller
|
|
|
|
if (relFontSize > 0) dir=1;
|
|
|
|
else dir = -1;
|
|
|
|
for (j=0; j<abs(relFontSize); j++)
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->RelativeFontChangeOnTextNode(dir, nodeAsText, 0, -1);
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (item)
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SetInlinePropertyOnNode(node, item->tag, &item->attr, &item->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 (NS_FAILED(res)) return res;
|
|
|
|
// we own item now (TakeSetProperty hands ownership to us)
|
|
|
|
delete item;
|
2001-01-28 23:13:07 +03:00
|
|
|
mHTMLEditor->mTypeInState->TakeSetProperty(&item);
|
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
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
}
|
2000-05-13 03:43:50 +04:00
|
|
|
if (weDidSometing)
|
|
|
|
return aSelection->Collapse(node, offset);
|
|
|
|
|
|
|
|
return res;
|
2000-03-29 16:53:23 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-08-10 01:50:02 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// IsEmptyBlock: figure out if aNode is (or is inside) an empty block.
|
|
|
|
// A block can have children and still be considered empty,
|
|
|
|
// if the children are empty or non-editable.
|
|
|
|
//
|
|
|
|
nsresult
|
1999-11-01 18:15:35 +03:00
|
|
|
nsHTMLEditRules::IsEmptyBlock(nsIDOMNode *aNode,
|
|
|
|
PRBool *outIsEmptyBlock,
|
|
|
|
PRBool aMozBRDoesntCount,
|
|
|
|
PRBool aListItemsNotEmpty)
|
1999-08-10 01:50:02 +04:00
|
|
|
{
|
|
|
|
if (!aNode || !outIsEmptyBlock) return NS_ERROR_NULL_POINTER;
|
|
|
|
*outIsEmptyBlock = PR_TRUE;
|
|
|
|
|
1999-09-11 04:20:59 +04:00
|
|
|
// nsresult res = NS_OK;
|
1999-09-06 23:51:59 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> nodeToTest;
|
|
|
|
if (nsEditor::IsBlockNode(aNode)) nodeToTest = do_QueryInterface(aNode);
|
1999-11-01 18:15:35 +03:00
|
|
|
// else nsCOMPtr<nsIDOMElement> block;
|
|
|
|
// looks like I forgot to finish this. Wonder what I was going to do?
|
1999-09-06 23:51:59 +04:00
|
|
|
|
|
|
|
if (!nodeToTest) return NS_ERROR_NULL_POINTER;
|
2001-01-28 23:13:07 +03:00
|
|
|
return mHTMLEditor->IsEmptyNode(nodeToTest, outIsEmptyBlock,
|
2000-01-26 03:57:37 +03:00
|
|
|
aMozBRDoesntCount, aListItemsNotEmpty);
|
1999-09-06 23:51:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-01-26 03:57:37 +03:00
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::WillAlign(nsISelection *aSelection,
|
2000-01-26 03:57:37 +03:00
|
|
|
const nsString *alignType,
|
|
|
|
PRBool *aCancel,
|
|
|
|
PRBool *aHandled)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
2000-01-26 03:57:37 +03:00
|
|
|
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
1999-11-25 03:19:45 +03:00
|
|
|
|
2000-01-26 03:57:37 +03:00
|
|
|
nsresult res = WillInsert(aSelection, aCancel);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// initialize out param
|
|
|
|
// we want to ignore result of WillInsert()
|
|
|
|
*aCancel = PR_FALSE;
|
|
|
|
*aHandled = PR_FALSE;
|
1999-11-25 03:19:45 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
|
2000-01-26 03:57:37 +03:00
|
|
|
|
2000-08-26 08:03:50 +04:00
|
|
|
// convert the selection ranges into "promoted" selection ranges:
|
|
|
|
// this basically just expands the range to include the immediate
|
|
|
|
// block parent, and then further expands to include any ancestors
|
|
|
|
// whose children are all in the range
|
|
|
|
*aHandled = PR_TRUE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfRanges;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetPromotedRanges(aSelection, address_of(arrayOfRanges), kAlign);
|
2000-01-26 03:57:37 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-08-26 08:03:50 +04:00
|
|
|
|
|
|
|
// use these ranges to contruct a list of nodes to act on.
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetNodesForOperation(arrayOfRanges, address_of(arrayOfNodes), kAlign);
|
2000-08-26 08:03:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2000-09-14 09:59:19 +04:00
|
|
|
// if we don't have any nodes, or we have only a single br, then we are
|
|
|
|
// creating an empty alignment div. We have to do some different things for these.
|
|
|
|
PRBool emptyDiv = PR_FALSE;
|
2000-08-26 08:03:50 +04:00
|
|
|
PRUint32 listCount;
|
|
|
|
arrayOfNodes->Count(&listCount);
|
2000-09-14 09:59:19 +04:00
|
|
|
if (!listCount) emptyDiv = PR_TRUE;
|
|
|
|
if (listCount == 1)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
|
|
|
|
nsCOMPtr<nsIDOMNode> theNode( do_QueryInterface(isupports ) );
|
|
|
|
if (nsHTMLEditUtils::IsBreak(theNode))
|
|
|
|
{
|
|
|
|
emptyDiv = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (emptyDiv)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
2000-01-26 03:57:37 +03:00
|
|
|
PRInt32 offset;
|
2000-06-29 13:23:41 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> brNode, parent, theDiv, sib;
|
2000-04-18 11:52:02 +04:00
|
|
|
nsAutoString divType; divType.AssignWithConversion("div");
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(parent), &offset);
|
2000-01-26 03:57:37 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = SplitAsNeeded(&divType, address_of(parent), &offset);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-06-29 13:23:41 +04:00
|
|
|
// consume a trailing br, if any. This is to keep an alignment from
|
|
|
|
// creating extra lines, if possible.
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNextHTMLNode(parent, offset, address_of(brNode));
|
2000-06-29 13:23:41 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-08-26 08:03:50 +04:00
|
|
|
if (brNode && nsHTMLEditUtils::IsBreak(brNode))
|
2000-06-29 13:23:41 +04:00
|
|
|
{
|
|
|
|
// making use of html structure... if next node after where
|
|
|
|
// we are putting our div is not a block, then the br we
|
|
|
|
// found is in same block we are, so its safe to consume it.
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNextHTMLSibling(parent, offset, address_of(sib));
|
2000-06-29 13:23:41 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!nsEditor::IsBlockNode(sib))
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(brNode);
|
2000-06-29 13:23:41 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateNode(divType, parent, offset, getter_AddRefs(theDiv));
|
2000-01-26 03:57:37 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// set up the alignment on the div
|
|
|
|
nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(theDiv);
|
2000-04-18 11:52:02 +04:00
|
|
|
nsAutoString attr; attr.AssignWithConversion("align");
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
|
2000-01-26 03:57:37 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
*aHandled = PR_TRUE;
|
|
|
|
// put in a moz-br so that it won't get deleted
|
2000-12-09 07:46:08 +03:00
|
|
|
res = CreateMozBR(theDiv, 0, address_of(brNode));
|
2000-01-26 03:57:37 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = aSelection->Collapse(theDiv, 0);
|
2000-08-26 08:03:50 +04:00
|
|
|
selectionResetter.Abort(); // dont reset our selection in this case.
|
2000-01-26 03:57:37 +03:00
|
|
|
return res;
|
|
|
|
}
|
1999-11-25 03:19:45 +03:00
|
|
|
|
2000-01-26 03:57:37 +03:00
|
|
|
// Next we detect all the transitions in the array, where a transition
|
|
|
|
// means that adjacent nodes in the array don't have the same parent.
|
|
|
|
|
|
|
|
nsVoidArray transitionList;
|
|
|
|
res = MakeTransitionList(arrayOfNodes, &transitionList);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// Ok, now go through all the nodes and give them an align attrib or put them in a div,
|
|
|
|
// or whatever is appropriate. Wohoo!
|
|
|
|
|
|
|
|
PRInt32 i;
|
|
|
|
nsCOMPtr<nsIDOMNode> curParent;
|
|
|
|
nsCOMPtr<nsIDOMNode> curDiv;
|
|
|
|
for (i=0; i<(PRInt32)listCount; i++)
|
|
|
|
{
|
|
|
|
// here's where we actually figure out what to do
|
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
|
|
|
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
|
|
|
|
PRInt32 offset;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
|
2000-01-26 03:57:37 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// if it's a div, don't nest it, just set the alignment
|
|
|
|
if (nsHTMLEditUtils::IsDiv(curNode))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(curNode);
|
2000-04-18 11:52:02 +04:00
|
|
|
nsAutoString attr; attr.AssignWithConversion("align");
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
|
2000-01-26 03:57:37 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// clear out curDiv so that we don't put nodes after this one into it
|
|
|
|
curDiv = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2000-08-26 08:03:50 +04:00
|
|
|
// if it's a table element (but not a table) or a list item, forget any "current" div, and
|
|
|
|
// instead put divs inside the appropriate block (td, li, etc)
|
|
|
|
if ( (nsHTMLEditUtils::IsTableElement(curNode) && !nsHTMLEditUtils::IsTable(curNode))
|
|
|
|
|| nsHTMLEditUtils::IsListItem(curNode) )
|
2000-02-25 07:39:30 +03:00
|
|
|
{
|
2000-08-26 08:03:50 +04:00
|
|
|
res = AlignInnerBlocks(curNode, alignType);
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// clear out curDiv so that we don't put nodes after this one into it
|
|
|
|
curDiv = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2000-01-26 03:57:37 +03:00
|
|
|
// need to make a div to put things in if we haven't already,
|
|
|
|
// or if this node doesn't go in div we used earlier.
|
|
|
|
if (!curDiv || transitionList[i])
|
|
|
|
{
|
2000-04-18 11:52:02 +04:00
|
|
|
nsAutoString divType; divType.AssignWithConversion("div");
|
2000-12-09 07:46:08 +03:00
|
|
|
res = SplitAsNeeded(&divType, address_of(curParent), &offset);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateNode(divType, curParent, offset, getter_AddRefs(curDiv));
|
2000-01-26 03:57:37 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// set up the alignment on the div
|
|
|
|
nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(curDiv);
|
2000-04-18 11:52:02 +04:00
|
|
|
nsAutoString attr; attr.AssignWithConversion("align");
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
|
2000-01-26 03:57:37 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// curDiv is now the correct thing to put curNode in
|
|
|
|
}
|
|
|
|
|
|
|
|
// tuck the node into the end of the active div
|
|
|
|
PRUint32 listLen;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetLengthOfDOMNode(curDiv, listLen);
|
2000-01-26 03:57:37 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->MoveNode(curNode, curDiv, listLen);
|
2000-01-26 03:57:37 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
1999-09-30 00:08:15 +04:00
|
|
|
return res;
|
|
|
|
}
|
2000-01-26 03:57:37 +03:00
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
|
2000-02-25 07:39:30 +03:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2000-08-26 08:03:50 +04:00
|
|
|
// AlignInnerBlocks: align inside table cells or list items
|
|
|
|
//
|
2000-02-25 07:39:30 +03:00
|
|
|
nsresult
|
2000-08-26 08:03:50 +04:00
|
|
|
nsHTMLEditRules::AlignInnerBlocks(nsIDOMNode *aNode, const nsString *alignType)
|
2000-02-25 07:39:30 +03:00
|
|
|
{
|
|
|
|
if (!aNode || !alignType) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult res;
|
|
|
|
|
2000-08-26 08:03:50 +04:00
|
|
|
// gather list of table cells or list items
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
|
|
|
nsTableCellAndListItemFunctor functor;
|
|
|
|
nsDOMIterator iter;
|
|
|
|
res = iter.Init(aNode);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = iter.MakeList(functor, address_of(arrayOfNodes));
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// now that we have the list, align their contents as requested
|
|
|
|
PRUint32 listCount;
|
|
|
|
PRUint32 j;
|
2000-08-26 08:03:50 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
nsCOMPtr<nsISupports> isupports;
|
|
|
|
|
2000-02-25 07:39:30 +03:00
|
|
|
arrayOfNodes->Count(&listCount);
|
|
|
|
for (j = 0; j < listCount; j++)
|
|
|
|
{
|
|
|
|
isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
|
|
|
|
node = do_QueryInterface(isupports);
|
2000-08-26 08:03:50 +04:00
|
|
|
res = AlignBlockContents(node, alignType);
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
arrayOfNodes->RemoveElementAt(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2000-08-26 08:03:50 +04:00
|
|
|
// AlignBlockContents: align contents of a block element
|
2000-02-25 07:39:30 +03:00
|
|
|
//
|
|
|
|
nsresult
|
2000-08-26 08:03:50 +04:00
|
|
|
nsHTMLEditRules::AlignBlockContents(nsIDOMNode *aNode, const nsString *alignType)
|
2000-02-25 07:39:30 +03:00
|
|
|
{
|
|
|
|
if (!aNode || !alignType) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult res;
|
|
|
|
nsCOMPtr <nsIDOMNode> firstChild, lastChild, divNode;
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetFirstEditableChild(aNode, address_of(firstChild));
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetLastEditableChild(aNode, address_of(lastChild));
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!firstChild)
|
|
|
|
{
|
|
|
|
// this cell has no content, nothing to align
|
|
|
|
}
|
|
|
|
else if ((firstChild==lastChild) && nsHTMLEditUtils::IsDiv(firstChild))
|
|
|
|
{
|
|
|
|
// the cell already has a div containing all of it's content: just
|
|
|
|
// act on this div.
|
|
|
|
nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(firstChild);
|
2000-04-18 11:52:02 +04:00
|
|
|
nsAutoString attr; attr.AssignWithConversion("align");
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-08-26 08:03:50 +04:00
|
|
|
// else we need to put in a div, set the alignment, and toss in all the children
|
2000-04-18 11:52:02 +04:00
|
|
|
nsAutoString divType; divType.AssignWithConversion("div");
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateNode(divType, aNode, 0, getter_AddRefs(divNode));
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// set up the alignment on the div
|
|
|
|
nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(divNode);
|
2000-04-18 11:52:02 +04:00
|
|
|
nsAutoString attr; attr.AssignWithConversion("align");
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// tuck the children into the end of the active div
|
|
|
|
while (lastChild && (lastChild != divNode))
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->MoveNode(lastChild, divNode, 0);
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetLastEditableChild(aNode, address_of(lastChild));
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-06-02 11:47:53 +04:00
|
|
|
|
2000-02-25 07:39:30 +03:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2000-06-02 11:47:53 +04:00
|
|
|
// GetInnerContent: aList and aTbl allow the caller to specify what kind
|
|
|
|
// of content to "look inside". If aTbl is true, look inside
|
|
|
|
// any table content, and append the inner content to the
|
|
|
|
// supplied issupportsarray. Similarly with aList and list content.
|
2000-02-25 07:39:30 +03:00
|
|
|
//
|
|
|
|
nsresult
|
2000-06-02 11:47:53 +04:00
|
|
|
nsHTMLEditRules::GetInnerContent(nsIDOMNode *aNode, nsISupportsArray *outArrayOfNodes, PRBool aList, PRBool aTbl)
|
2000-02-25 07:39:30 +03:00
|
|
|
{
|
|
|
|
if (!aNode || !outArrayOfNodes) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
nsCOMPtr<nsISupports> isupports;
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res = mHTMLEditor->GetFirstEditableChild(aNode, address_of(node));
|
2000-06-02 11:47:53 +04:00
|
|
|
while (NS_SUCCEEDED(res) && node)
|
2000-02-25 07:39:30 +03:00
|
|
|
{
|
2000-06-02 11:47:53 +04:00
|
|
|
if ( ( aList && (nsHTMLEditUtils::IsList(node) ||
|
|
|
|
nsHTMLEditUtils::IsListItem(node) ) )
|
2000-08-14 03:53:34 +04:00
|
|
|
|| ( aTbl && nsHTMLEditUtils::IsTableElement(node) ) )
|
2000-02-25 07:39:30 +03:00
|
|
|
{
|
2000-06-02 11:47:53 +04:00
|
|
|
res = GetInnerContent(node, outArrayOfNodes, aList, aTbl);
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
2000-06-02 11:47:53 +04:00
|
|
|
else
|
2000-06-02 10:03:46 +04:00
|
|
|
{
|
2000-06-02 11:47:53 +04:00
|
|
|
isupports = do_QueryInterface(node);
|
|
|
|
outArrayOfNodes->AppendElement(isupports);
|
2000-06-02 10:03:46 +04:00
|
|
|
}
|
2000-06-02 11:47:53 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> tmp;
|
|
|
|
res = node->GetNextSibling(getter_AddRefs(tmp));
|
|
|
|
node = tmp;
|
2000-06-02 10:03:46 +04:00
|
|
|
}
|
2000-06-02 11:47:53 +04:00
|
|
|
|
2000-06-02 10:03:46 +04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
1999-06-16 09:02:43 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// IsFirstNode: Are we the first edittable node in our parent?
|
|
|
|
//
|
|
|
|
PRBool
|
|
|
|
nsHTMLEditRules::IsFirstNode(nsIDOMNode *aNode)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
PRInt32 offset, j=0;
|
2000-12-09 07:46:08 +03:00
|
|
|
nsresult res = nsEditor::GetNodeLocation(aNode, address_of(parent), &offset);
|
1999-11-29 11:28:46 +03:00
|
|
|
if (NS_FAILED(res))
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("failure in nsHTMLEditRules::IsFirstNode");
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
1999-06-16 09:02:43 +04:00
|
|
|
if (!offset) // easy case, we are first dom child
|
|
|
|
return PR_TRUE;
|
1999-11-29 11:28:46 +03:00
|
|
|
if (!parent)
|
|
|
|
return PR_TRUE;
|
1999-06-16 09:02:43 +04:00
|
|
|
|
|
|
|
// ok, so there are earlier children. But are they editable???
|
2000-01-26 03:57:37 +03:00
|
|
|
nsCOMPtr<nsIDOMNodeList> childList;
|
1999-06-16 09:02:43 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> child;
|
1999-11-18 01:34:41 +03:00
|
|
|
|
1999-11-29 11:28:46 +03:00
|
|
|
res = parent->GetChildNodes(getter_AddRefs(childList));
|
|
|
|
if (NS_FAILED(res) || !childList)
|
|
|
|
{
|
2000-01-26 03:57:37 +03:00
|
|
|
NS_NOTREACHED("failure in nsHTMLEditUtils::IsFirstNode");
|
1999-11-29 11:28:46 +03:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
1999-06-16 09:02:43 +04:00
|
|
|
while (j < offset)
|
|
|
|
{
|
|
|
|
childList->Item(j, getter_AddRefs(child));
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->IsEditable(child))
|
1999-06-16 09:02:43 +04:00
|
|
|
return PR_FALSE;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// IsLastNode: Are we the first edittable node in our parent?
|
|
|
|
//
|
|
|
|
PRBool
|
|
|
|
nsHTMLEditRules::IsLastNode(nsIDOMNode *aNode)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
PRInt32 offset, j;
|
|
|
|
PRUint32 numChildren;
|
2000-12-09 07:46:08 +03:00
|
|
|
nsresult res = nsEditor::GetNodeLocation(aNode, address_of(parent), &offset);
|
1999-11-29 11:28:46 +03:00
|
|
|
if (NS_FAILED(res))
|
|
|
|
{
|
2000-01-26 03:57:37 +03:00
|
|
|
NS_NOTREACHED("failure in nsHTMLEditUtils::IsLastNode");
|
1999-11-29 11:28:46 +03:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
1999-06-16 09:02:43 +04:00
|
|
|
nsEditor::GetLengthOfDOMNode(parent, numChildren);
|
1999-09-11 04:20:59 +04:00
|
|
|
if (offset+1 == (PRInt32)numChildren) // easy case, we are last dom child
|
1999-06-16 09:02:43 +04:00
|
|
|
return PR_TRUE;
|
1999-11-29 11:28:46 +03:00
|
|
|
if (!parent)
|
|
|
|
return PR_TRUE;
|
|
|
|
|
1999-06-16 09:02:43 +04:00
|
|
|
// ok, so there are later children. But are they editable???
|
|
|
|
j = offset+1;
|
|
|
|
nsCOMPtr<nsIDOMNodeList>childList;
|
|
|
|
nsCOMPtr<nsIDOMNode> child;
|
1999-11-29 11:28:46 +03:00
|
|
|
res = parent->GetChildNodes(getter_AddRefs(childList));
|
|
|
|
if (NS_FAILED(res) || !childList)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("failure in nsHTMLEditRules::IsLastNode");
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
1999-09-11 04:20:59 +04:00
|
|
|
while (j < (PRInt32)numChildren)
|
1999-06-16 09:02:43 +04:00
|
|
|
{
|
|
|
|
childList->Item(j, getter_AddRefs(child));
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->IsEditable(child))
|
1999-06-16 09:02:43 +04:00
|
|
|
return PR_FALSE;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-09-30 00:08:15 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// AtStartOfBlock: is node/offset at the start of the editable material in this block?
|
|
|
|
//
|
|
|
|
PRBool
|
|
|
|
nsHTMLEditRules::AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(aNode);
|
|
|
|
if (nodeAsText && aOffset) return PR_FALSE; // there are chars in front of us
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> priorNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res = mHTMLEditor->GetPriorHTMLNode(aNode, aOffset, address_of(priorNode));
|
1999-09-30 00:08:15 +04:00
|
|
|
if (NS_FAILED(res)) return PR_TRUE;
|
|
|
|
if (!priorNode) return PR_TRUE;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> blockParent = mHTMLEditor->GetBlockNodeParent(priorNode);
|
1999-09-30 00:08:15 +04:00
|
|
|
if (blockParent && (blockParent.get() == aBlock)) return PR_FALSE;
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// AtEndOfBlock: is node/offset at the end of the editable material in this block?
|
|
|
|
//
|
|
|
|
PRBool
|
|
|
|
nsHTMLEditRules::AtEndOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(aNode);
|
|
|
|
if (nodeAsText)
|
|
|
|
{
|
|
|
|
PRUint32 strLength;
|
|
|
|
nodeAsText->GetLength(&strLength);
|
1999-11-29 11:28:46 +03:00
|
|
|
if ((PRInt32)strLength > aOffset) return PR_FALSE; // there are chars in after us
|
1999-09-30 00:08:15 +04:00
|
|
|
}
|
|
|
|
nsCOMPtr<nsIDOMNode> nextNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res = mHTMLEditor->GetNextHTMLNode(aNode, aOffset, address_of(nextNode));
|
1999-09-30 00:08:15 +04:00
|
|
|
if (NS_FAILED(res)) return PR_TRUE;
|
|
|
|
if (!nextNode) return PR_TRUE;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> blockParent = mHTMLEditor->GetBlockNodeParent(nextNode);
|
1999-09-30 00:08:15 +04:00
|
|
|
if (blockParent && (blockParent.get() == aBlock)) return PR_FALSE;
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-01-26 03:57:37 +03:00
|
|
|
// not needed at moment - leaving around in case we go back to it.
|
|
|
|
#if 0
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// CreateMozDiv: makes a div with type = _moz
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::CreateMozDiv(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outDiv)
|
|
|
|
{
|
|
|
|
if (!inParent || !outDiv) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsAutoString divType= "div";
|
|
|
|
*outDiv = nsnull;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res = mHTMLEditor->CreateNode(divType, inParent, inOffset, getter_AddRefs(*outDiv));
|
2000-01-26 03:57:37 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// give it special moz attr
|
|
|
|
nsCOMPtr<nsIDOMElement> mozDivElem = do_QueryInterface(*outDiv);
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SetAttribute(mozDivElem, "type", "_moz");
|
2000-01-26 03:57:37 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = AddTrailerBR(*outDiv);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
1999-06-16 09:02:43 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetPromotedPoint: figure out where a start or end point for a block
|
|
|
|
// operation really is
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt32 aOffset,
|
|
|
|
PRInt32 actionID, nsCOMPtr<nsIDOMNode> *outNode, PRInt32 *outOffset)
|
|
|
|
{
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
nsCOMPtr<nsIDOMNode> node = aNode;
|
|
|
|
nsCOMPtr<nsIDOMNode> parent = aNode;
|
|
|
|
PRInt32 offset = aOffset;
|
|
|
|
|
2000-05-03 04:14:28 +04:00
|
|
|
// defualt values
|
|
|
|
*outNode = node;
|
|
|
|
*outOffset = offset;
|
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
// we do one thing for InsertText actions, something else entirely for other actions
|
|
|
|
if (actionID == kInsertText)
|
|
|
|
{
|
|
|
|
PRBool isSpace, isNBSP;
|
|
|
|
nsCOMPtr<nsIDOMNode> temp;
|
|
|
|
// for insert text or delete actions, we want to look backwards (or forwards, as appropriate)
|
|
|
|
// for additional whitespace or nbsp's. We may have to act on these later even though
|
|
|
|
// they are outside of the initial selection. Even if they are in another node!
|
|
|
|
if (aWhere == kStart)
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->IsPrevCharWhitespace(node, offset, &isSpace, &isNBSP, address_of(temp), &offset);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (isSpace || isNBSP) node = temp;
|
|
|
|
else break;
|
|
|
|
} while (node);
|
|
|
|
|
|
|
|
*outNode = node;
|
|
|
|
*outOffset = offset;
|
|
|
|
}
|
|
|
|
else if (aWhere == kEnd)
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->IsNextCharWhitespace(node, offset, &isSpace, &isNBSP, address_of(temp), &offset);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (isSpace || isNBSP) node = temp;
|
|
|
|
else break;
|
|
|
|
} while (node);
|
|
|
|
|
|
|
|
*outNode = node;
|
|
|
|
*outOffset = offset;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
// else not kInsertText. In this case we want to see if we should
|
2000-03-24 03:26:47 +03:00
|
|
|
// grab any adjacent inline nodes and/or parents and other ancestors
|
1999-06-16 09:02:43 +04:00
|
|
|
if (aWhere == kStart)
|
|
|
|
{
|
|
|
|
// some special casing for text nodes
|
|
|
|
if (nsEditor::IsTextNode(aNode))
|
|
|
|
{
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(aNode, address_of(parent), &offset);
|
1999-08-18 12:13:06 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-06-16 09:02:43 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
node = nsEditor::GetChildAt(parent,offset);
|
|
|
|
}
|
2000-04-19 01:39:35 +04:00
|
|
|
if (!node) node = parent;
|
|
|
|
|
1999-06-16 09:02:43 +04:00
|
|
|
|
2000-05-03 04:14:28 +04:00
|
|
|
// if this is an inline node,
|
1999-08-18 12:13:06 +04:00
|
|
|
// back up through any prior inline nodes that
|
|
|
|
// aren't across a <br> from us.
|
1999-08-10 03:39:48 +04:00
|
|
|
|
|
|
|
if (!nsEditor::IsBlockNode(node))
|
|
|
|
{
|
1999-08-18 12:13:06 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> block = nsEditor::GetBlockNodeParent(node);
|
2000-08-26 08:03:50 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> prevNode, prevNodeBlock;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetPriorHTMLNode(node, address_of(prevNode));
|
2000-08-26 08:03:50 +04:00
|
|
|
|
|
|
|
while (prevNode && NS_SUCCEEDED(res))
|
2000-05-03 04:14:28 +04:00
|
|
|
{
|
2000-08-26 08:03:50 +04:00
|
|
|
prevNodeBlock = nsEditor::GetBlockNodeParent(prevNode);
|
|
|
|
if (prevNodeBlock != block)
|
|
|
|
break;
|
2000-05-03 04:14:28 +04:00
|
|
|
if (nsHTMLEditUtils::IsBreak(prevNode))
|
|
|
|
break;
|
|
|
|
if (nsEditor::IsBlockNode(prevNode))
|
|
|
|
break;
|
|
|
|
node = prevNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetPriorHTMLNode(node, address_of(prevNode));
|
2000-05-03 04:14:28 +04:00
|
|
|
}
|
1999-08-10 03:39:48 +04:00
|
|
|
}
|
|
|
|
|
1999-06-16 09:02:43 +04:00
|
|
|
// finding the real start for this point. look up the tree for as long as we are the
|
|
|
|
// first node in the container, and as long as we haven't hit the body node.
|
2000-05-03 04:14:28 +04:00
|
|
|
if (!nsHTMLEditUtils::IsBody(node))
|
1999-06-16 09:02:43 +04:00
|
|
|
{
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(node, address_of(parent), &offset);
|
1999-06-16 09:02:43 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-05-03 04:14:28 +04:00
|
|
|
while ((IsFirstNode(node)) && (!nsHTMLEditUtils::IsBody(parent)))
|
|
|
|
{
|
2000-09-14 09:59:19 +04:00
|
|
|
// some cutoffs are here: we don't need to also include them in the aWhere == kEnd case.
|
|
|
|
// as long as they are in one or the other it will work.
|
|
|
|
|
|
|
|
// dont cross table cell boundaries
|
|
|
|
if (nsHTMLEditUtils::IsTableCell(parent)) break;
|
2000-08-26 08:03:50 +04:00
|
|
|
// special case for outdent: don't keep looking up
|
|
|
|
// if we have found a blockquote element to act on
|
|
|
|
if ((actionID == kOutdent) && nsHTMLEditUtils::IsBlockquote(parent))
|
|
|
|
break;
|
2000-05-03 04:14:28 +04:00
|
|
|
node = parent;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(node, address_of(parent), &offset);
|
2000-05-03 04:14:28 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
*outNode = parent;
|
|
|
|
*outOffset = offset;
|
|
|
|
return res;
|
|
|
|
}
|
1999-06-16 09:02:43 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (aWhere == kEnd)
|
|
|
|
{
|
|
|
|
// some special casing for text nodes
|
|
|
|
if (nsEditor::IsTextNode(aNode))
|
|
|
|
{
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(aNode, address_of(parent), &offset);
|
1999-11-29 11:28:46 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-06-16 09:02:43 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-04-19 01:39:35 +04:00
|
|
|
if (offset) offset--; // we want node _before_ offset
|
1999-06-16 09:02:43 +04:00
|
|
|
node = nsEditor::GetChildAt(parent,offset);
|
|
|
|
}
|
2000-04-19 01:39:35 +04:00
|
|
|
if (!node) node = parent;
|
1999-06-16 09:02:43 +04:00
|
|
|
|
2000-05-03 04:14:28 +04:00
|
|
|
// if this is an inline node,
|
1999-08-18 12:13:06 +04:00
|
|
|
// look ahead through any further inline nodes that
|
1999-08-10 03:39:48 +04:00
|
|
|
// aren't across a <br> from us, and that are enclosed in the same block.
|
|
|
|
|
|
|
|
if (!nsEditor::IsBlockNode(node))
|
|
|
|
{
|
1999-08-18 12:13:06 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> block = nsEditor::GetBlockNodeParent(node);
|
2000-08-26 08:03:50 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> nextNode, nextNodeBlock;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNextHTMLNode(node, address_of(nextNode));
|
2000-08-26 08:03:50 +04:00
|
|
|
|
|
|
|
while (nextNode && NS_SUCCEEDED(res))
|
2000-04-24 15:51:12 +04:00
|
|
|
{
|
2000-08-26 08:03:50 +04:00
|
|
|
nextNodeBlock = nsEditor::GetBlockNodeParent(nextNode);
|
|
|
|
if (nextNodeBlock != block)
|
|
|
|
break;
|
2000-05-03 04:14:28 +04:00
|
|
|
if (nsHTMLEditUtils::IsBreak(nextNode))
|
1999-08-18 12:13:06 +04:00
|
|
|
{
|
|
|
|
node = nextNode;
|
2000-04-24 15:51:12 +04:00
|
|
|
break;
|
1999-08-18 12:13:06 +04:00
|
|
|
}
|
2000-04-24 15:51:12 +04:00
|
|
|
if (nsEditor::IsBlockNode(nextNode))
|
|
|
|
break;
|
|
|
|
node = nextNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNextHTMLNode(node, address_of(nextNode));
|
2000-04-24 15:51:12 +04:00
|
|
|
}
|
1999-08-10 03:39:48 +04:00
|
|
|
}
|
|
|
|
|
1999-06-16 09:02:43 +04:00
|
|
|
// finding the real end for this point. look up the tree for as long as we are the
|
|
|
|
// last node in the container, and as long as we haven't hit the body node.
|
2000-05-03 04:14:28 +04:00
|
|
|
if (!nsHTMLEditUtils::IsBody(node))
|
1999-06-16 09:02:43 +04:00
|
|
|
{
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(node, address_of(parent), &offset);
|
1999-06-16 09:02:43 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-05-03 04:14:28 +04:00
|
|
|
while ((IsLastNode(node)) && (!nsHTMLEditUtils::IsBody(parent)))
|
|
|
|
{
|
|
|
|
node = parent;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(node, address_of(parent), &offset);
|
2000-05-03 04:14:28 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
*outNode = parent;
|
|
|
|
offset++; // add one since this in an endpoint - want to be AFTER node.
|
|
|
|
*outOffset = offset;
|
|
|
|
return res;
|
|
|
|
}
|
1999-06-16 09:02:43 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
1999-07-01 17:42:03 +04:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetPromotedRanges: run all the selection range endpoint through
|
|
|
|
// GetPromotedPoint()
|
|
|
|
//
|
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::GetPromotedRanges(nsISelection *inSelection,
|
1999-07-01 17:42:03 +04:00
|
|
|
nsCOMPtr<nsISupportsArray> *outArrayOfRanges,
|
|
|
|
PRInt32 inOperationType)
|
|
|
|
{
|
|
|
|
if (!inSelection || !outArrayOfRanges) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsresult res = NS_NewISupportsArray(getter_AddRefs(*outArrayOfRanges));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
PRInt32 rangeCount;
|
1999-07-18 06:27:19 +04:00
|
|
|
res = inSelection->GetRangeCount(&rangeCount);
|
1999-07-01 17:42:03 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
PRInt32 i;
|
|
|
|
nsCOMPtr<nsIDOMRange> selectionRange;
|
1999-11-25 03:19:45 +03:00
|
|
|
nsCOMPtr<nsIDOMRange> opRange;
|
1999-07-01 17:42:03 +04:00
|
|
|
|
|
|
|
for (i = 0; i < rangeCount; i++)
|
|
|
|
{
|
1999-07-18 06:27:19 +04:00
|
|
|
res = inSelection->GetRangeAt(i, getter_AddRefs(selectionRange));
|
1999-07-01 17:42:03 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-11-25 03:19:45 +03:00
|
|
|
|
|
|
|
// clone range so we dont muck with actual selection ranges
|
2000-08-24 07:54:30 +04:00
|
|
|
res = selectionRange->CloneRange(getter_AddRefs(opRange));
|
1999-07-01 17:42:03 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-11-25 03:19:45 +03:00
|
|
|
|
|
|
|
// make a new adjusted range to represent the appropriate block content.
|
|
|
|
// The basic idea is to push out the range endpoints
|
|
|
|
// to truly enclose the blocks that we will affect.
|
|
|
|
// This call alters opRange.
|
|
|
|
res = PromoteRange(opRange, inOperationType);
|
1999-07-01 17:42:03 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-11-25 03:19:45 +03:00
|
|
|
|
1999-07-01 17:42:03 +04:00
|
|
|
// stuff new opRange into nsISupportsArray
|
|
|
|
nsCOMPtr<nsISupports> isupports = do_QueryInterface(opRange);
|
|
|
|
(*outArrayOfRanges)->AppendElement(isupports);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2000-03-24 03:26:47 +03:00
|
|
|
// PromoteRange: expand a range to include any parents for which all
|
1999-11-25 03:19:45 +03:00
|
|
|
// editable children are already in range.
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::PromoteRange(nsIDOMRange *inRange,
|
|
|
|
PRInt32 inOperationType)
|
|
|
|
{
|
|
|
|
if (!inRange) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult res;
|
|
|
|
nsCOMPtr<nsIDOMNode> startNode, endNode;
|
|
|
|
PRInt32 startOffset, endOffset;
|
|
|
|
|
2000-08-24 07:54:30 +04:00
|
|
|
res = inRange->GetStartContainer(getter_AddRefs(startNode));
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = inRange->GetStartOffset(&startOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-08-24 07:54:30 +04:00
|
|
|
res = inRange->GetEndContainer(getter_AddRefs(endNode));
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = inRange->GetEndOffset(&endOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
// make a new adjusted range to represent the appropriate block content.
|
1999-11-25 03:19:45 +03:00
|
|
|
// this is tricky. the basic idea is to push out the range endpoints
|
|
|
|
// to truly enclose the blocks that we will affect
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> opStartNode;
|
|
|
|
nsCOMPtr<nsIDOMNode> opEndNode;
|
|
|
|
PRInt32 opStartOffset, opEndOffset;
|
|
|
|
nsCOMPtr<nsIDOMRange> opRange;
|
|
|
|
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetPromotedPoint( kStart, startNode, startOffset, inOperationType, address_of(opStartNode), &opStartOffset);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetPromotedPoint( kEnd, endNode, endOffset, inOperationType, address_of(opEndNode), &opEndOffset);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-02-25 07:39:30 +03:00
|
|
|
res = inRange->SetStart(opStartNode, opStartOffset);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-02-25 07:39:30 +03:00
|
|
|
res = inRange->SetEnd(opEndNode, opEndOffset);
|
1999-11-25 03:19:45 +03:00
|
|
|
return res;
|
|
|
|
}
|
1999-07-01 17:42:03 +04:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetNodesForOperation: run through the ranges in the array and construct
|
|
|
|
// a new array of nodes to be acted on.
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
|
|
|
|
nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
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
|
|
|
PRInt32 inOperationType,
|
|
|
|
PRBool aDontTouchContent)
|
1999-07-01 17:42:03 +04:00
|
|
|
{
|
|
|
|
if (!inArrayOfRanges || !outArrayOfNodes) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
2000-08-26 08:03:50 +04:00
|
|
|
// make a array
|
1999-07-01 17:42:03 +04:00
|
|
|
nsresult res = NS_NewISupportsArray(getter_AddRefs(*outArrayOfNodes));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
PRUint32 rangeCount;
|
|
|
|
res = inArrayOfRanges->Count(&rangeCount);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
PRInt32 i;
|
|
|
|
nsCOMPtr<nsIDOMRange> opRange;
|
|
|
|
nsCOMPtr<nsISupports> isupports;
|
|
|
|
|
2000-08-26 08:03:50 +04:00
|
|
|
// bust up any inlines that cross our range endpoints,
|
|
|
|
// but only if we are allowed to touch content.
|
|
|
|
|
|
|
|
if (!aDontTouchContent)
|
|
|
|
{
|
|
|
|
nsVoidArray rangeItemArray;
|
|
|
|
// first register ranges for special editor gravity
|
|
|
|
for (i = 0; i < (PRInt32)rangeCount; i++)
|
|
|
|
{
|
2000-10-11 04:24:23 +04:00
|
|
|
isupports = (dont_AddRef)(inArrayOfRanges->ElementAt(0));
|
2000-08-26 08:03:50 +04:00
|
|
|
opRange = do_QueryInterface(isupports);
|
|
|
|
nsRangeStore *item = new nsRangeStore();
|
|
|
|
if (!item) return NS_ERROR_NULL_POINTER;
|
|
|
|
item->StoreRange(opRange);
|
2001-01-28 23:13:07 +03:00
|
|
|
mHTMLEditor->mRangeUpdater.RegisterRangeItem(item);
|
2000-08-26 08:03:50 +04:00
|
|
|
rangeItemArray.AppendElement((void*)item);
|
|
|
|
inArrayOfRanges->RemoveElementAt(0);
|
|
|
|
}
|
|
|
|
// now bust up inlines
|
|
|
|
for (i = (PRInt32)rangeCount-1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
nsRangeStore *item = (nsRangeStore*)rangeItemArray.ElementAt(i);
|
|
|
|
res = BustUpInlinesAtRangeEndpoints(*item);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
// then unregister the ranges
|
|
|
|
for (i = 0; i < (PRInt32)rangeCount; i++)
|
|
|
|
{
|
|
|
|
nsRangeStore *item = (nsRangeStore*)rangeItemArray.ElementAt(0);
|
|
|
|
if (!item) return NS_ERROR_NULL_POINTER;
|
2000-10-11 04:24:23 +04:00
|
|
|
rangeItemArray.RemoveElementAt(0);
|
2001-01-28 23:13:07 +03:00
|
|
|
mHTMLEditor->mRangeUpdater.DropRangeItem(item);
|
2000-12-09 07:46:08 +03:00
|
|
|
res = item->GetRange(address_of(opRange));
|
2000-08-26 08:03:50 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-08-30 08:26:55 +04:00
|
|
|
delete item;
|
2000-11-30 01:06:02 +03:00
|
|
|
isupports = do_QueryInterface(opRange);
|
2000-08-26 08:03:50 +04:00
|
|
|
inArrayOfRanges->AppendElement(isupports);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// gather up a list of all the nodes
|
1999-09-11 04:20:59 +04:00
|
|
|
for (i = 0; i < (PRInt32)rangeCount; i++)
|
1999-07-01 17:42:03 +04:00
|
|
|
{
|
|
|
|
isupports = (dont_AddRef)(inArrayOfRanges->ElementAt(i));
|
|
|
|
opRange = do_QueryInterface(isupports);
|
|
|
|
|
2000-08-26 08:03:50 +04:00
|
|
|
nsTrivialFunctor functor;
|
|
|
|
nsDOMSubtreeIterator iter;
|
|
|
|
res = iter.Init(opRange);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = iter.AppendList(functor, *outArrayOfNodes);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
// certain operations should not act on li's and td's, but rather inside
|
|
|
|
// them. alter the list as needed
|
|
|
|
if ( (inOperationType == kMakeBasicBlock) ||
|
|
|
|
(inOperationType == kAlign) )
|
|
|
|
{
|
|
|
|
PRUint32 listCount;
|
|
|
|
(*outArrayOfNodes)->Count(&listCount);
|
|
|
|
for (i=(PRInt32)listCount-1; i>=0; i--)
|
1999-07-01 17:42:03 +04:00
|
|
|
{
|
2000-11-30 01:06:02 +03:00
|
|
|
isupports = (dont_AddRef)((*outArrayOfNodes)->ElementAt(i));
|
2000-08-26 08:03:50 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> node( do_QueryInterface(isupports) );
|
|
|
|
if ( (nsHTMLEditUtils::IsTableElement(node) && !nsHTMLEditUtils::IsTable(node))
|
|
|
|
|| (nsHTMLEditUtils::IsListItem(node)))
|
|
|
|
{
|
|
|
|
(*outArrayOfNodes)->RemoveElementAt(i);
|
|
|
|
res = GetInnerContent(node, *outArrayOfNodes);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// indent/outdent already do something special for list items, but
|
|
|
|
// we still need to make sure we dont act on table elements
|
|
|
|
else if ( (inOperationType == kOutdent) ||
|
|
|
|
(inOperationType == kIndent) )
|
|
|
|
{
|
|
|
|
PRUint32 listCount;
|
|
|
|
(*outArrayOfNodes)->Count(&listCount);
|
|
|
|
for (i=(PRInt32)listCount-1; i>=0; i--)
|
|
|
|
{
|
2000-11-30 01:06:02 +03:00
|
|
|
isupports = (dont_AddRef)((*outArrayOfNodes)->ElementAt(i));
|
2000-08-26 08:03:50 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> node( do_QueryInterface(isupports) );
|
|
|
|
if ( (nsHTMLEditUtils::IsTableElement(node) && !nsHTMLEditUtils::IsTable(node)) )
|
|
|
|
{
|
|
|
|
(*outArrayOfNodes)->RemoveElementAt(i);
|
|
|
|
res = GetInnerContent(node, *outArrayOfNodes);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
1999-07-01 17:42:03 +04:00
|
|
|
}
|
|
|
|
}
|
2000-08-26 08:03:50 +04:00
|
|
|
|
|
|
|
|
2000-04-24 15:51:12 +04:00
|
|
|
// post process the list to break up inline containers that contain br's.
|
|
|
|
// but only for operations that might care, like making lists or para's...
|
|
|
|
if ( (inOperationType == kMakeBasicBlock) ||
|
2000-08-26 08:03:50 +04:00
|
|
|
(inOperationType == kMakeList) ||
|
|
|
|
(inOperationType == kAlign) ||
|
|
|
|
(inOperationType == kIndent) ||
|
|
|
|
(inOperationType == kOutdent) )
|
2000-04-24 15:51:12 +04:00
|
|
|
{
|
|
|
|
PRUint32 listCount;
|
|
|
|
(*outArrayOfNodes)->Count(&listCount);
|
|
|
|
for (i=(PRInt32)listCount-1; i>=0; i--)
|
|
|
|
{
|
2000-11-30 01:06:02 +03:00
|
|
|
isupports = (dont_AddRef)((*outArrayOfNodes)->ElementAt(i));
|
2000-04-24 15:51:12 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> node( do_QueryInterface(isupports) );
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!aDontTouchContent && mHTMLEditor->IsInlineNode(node)
|
|
|
|
&& mHTMLEditor->IsContainer(node) && !mHTMLEditor->IsTextNode(node))
|
2000-04-24 15:51:12 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfInlines;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = BustUpInlinesAtBRs(node, address_of(arrayOfInlines));
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// put these nodes in outArrayOfNodes, replacing the current node
|
|
|
|
(*outArrayOfNodes)->RemoveElementAt((PRUint32)i);
|
|
|
|
// i sure wish nsISupportsArray had an IsEmpty() and DeleteLastElement()
|
|
|
|
// calls. For that matter, if I could just insert one nsISupportsArray
|
|
|
|
// into another at a given position, that would do everything I need here.
|
|
|
|
PRUint32 iCount;
|
|
|
|
arrayOfInlines->Count(&iCount);
|
|
|
|
while (iCount)
|
|
|
|
{
|
|
|
|
iCount--;
|
|
|
|
isupports = (dont_AddRef)(arrayOfInlines->ElementAt(iCount));
|
|
|
|
(*outArrayOfNodes)->InsertElementAt(isupports, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-07-01 17:42:03 +04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
1999-08-18 12:13:06 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetChildNodesForOperation:
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::GetChildNodesForOperation(nsIDOMNode *inNode,
|
|
|
|
nsCOMPtr<nsISupportsArray> *outArrayOfNodes)
|
|
|
|
{
|
|
|
|
if (!inNode || !outArrayOfNodes) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsresult res = NS_NewISupportsArray(getter_AddRefs(*outArrayOfNodes));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNodeList> childNodes;
|
|
|
|
res = inNode->GetChildNodes(getter_AddRefs(childNodes));
|
|
|
|
if (NS_FAILED(res)) return res;
|
1999-11-29 11:28:46 +03:00
|
|
|
if (!childNodes) return NS_ERROR_NULL_POINTER;
|
1999-08-18 12:13:06 +04:00
|
|
|
PRUint32 childCount;
|
|
|
|
res = childNodes->GetLength(&childCount);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
PRUint32 i;
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
nsCOMPtr<nsISupports> isupports;
|
|
|
|
for (i = 0; i < childCount; i++)
|
|
|
|
{
|
|
|
|
res = childNodes->Item( i, getter_AddRefs(node));
|
|
|
|
if (!node) return NS_ERROR_FAILURE;
|
|
|
|
isupports = do_QueryInterface(node);
|
|
|
|
(*outArrayOfNodes)->AppendElement(isupports);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-03 04:14:28 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetListActionNodes:
|
|
|
|
//
|
|
|
|
nsresult
|
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
|
|
|
nsHTMLEditRules::GetListActionNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
2000-09-14 09:59:19 +04:00
|
|
|
PRBool aEntireList,
|
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
|
|
|
PRBool aDontTouchContent)
|
2000-05-03 04:14:28 +04:00
|
|
|
{
|
|
|
|
if (!outArrayOfNodes) return NS_ERROR_NULL_POINTER;
|
2000-09-14 09:59:19 +04:00
|
|
|
nsresult res = NS_OK;
|
2000-05-03 04:14:28 +04:00
|
|
|
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection>selection;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
|
2000-05-03 04:14:28 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
|
|
|
|
if (!selPriv)
|
|
|
|
return NS_ERROR_FAILURE;
|
2000-09-14 09:59:19 +04:00
|
|
|
// added this in so that ui code can ask to change an entire list, even if selection
|
|
|
|
// is only in part of it. used by list item dialog.
|
|
|
|
if (aEntireList)
|
|
|
|
{
|
|
|
|
res = NS_NewISupportsArray(getter_AddRefs(*outArrayOfNodes));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
nsCOMPtr<nsIEnumerator> enumerator;
|
2000-09-14 15:45:01 +04:00
|
|
|
res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
|
2000-09-14 09:59:19 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!enumerator) return NS_ERROR_UNEXPECTED;
|
|
|
|
|
|
|
|
for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next())
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupports> currentItem;
|
|
|
|
res = enumerator->CurrentItem(getter_AddRefs(currentItem));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!currentItem) return NS_ERROR_UNEXPECTED;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
|
|
|
|
nsCOMPtr<nsIDOMNode> commonParent, parent, tmp;
|
|
|
|
range->GetCommonAncestorContainer(getter_AddRefs(commonParent));
|
|
|
|
if (commonParent)
|
|
|
|
{
|
|
|
|
parent = commonParent;
|
|
|
|
while (parent)
|
|
|
|
{
|
|
|
|
if (nsHTMLEditUtils::IsList(parent))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupports> isupports = do_QueryInterface(parent);
|
|
|
|
(*outArrayOfNodes)->AppendElement(isupports);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
parent->GetParentNode(getter_AddRefs(tmp));
|
|
|
|
parent = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if we didn't find any nodes this way, then try the normal way. perhaps the
|
|
|
|
// selection spans multiple lists but with no common list parent.
|
|
|
|
if (*outArrayOfNodes)
|
|
|
|
{
|
|
|
|
PRUint32 nodeCount;
|
|
|
|
(*outArrayOfNodes)->Count(&nodeCount);
|
|
|
|
if (nodeCount) return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-05-03 04:14:28 +04:00
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfRanges;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetPromotedRanges(selection, address_of(arrayOfRanges), kMakeList);
|
2000-05-03 04:14:28 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// use these ranges to contruct a list of nodes to act on.
|
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
|
|
|
res = GetNodesForOperation(arrayOfRanges, outArrayOfNodes, kMakeList, aDontTouchContent);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// pre process our list of nodes...
|
|
|
|
PRUint32 listCount;
|
|
|
|
PRInt32 i;
|
|
|
|
(*outArrayOfNodes)->Count(&listCount);
|
|
|
|
for (i=(PRInt32)listCount-1; i>=0; i--)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)((*outArrayOfNodes)->ElementAt(i));
|
|
|
|
nsCOMPtr<nsIDOMNode> testNode( do_QueryInterface(isupports ) );
|
|
|
|
|
|
|
|
// Remove all non-editable nodes. Leave them be.
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!mHTMLEditor->IsEditable(testNode))
|
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
|
|
|
{
|
|
|
|
(*outArrayOfNodes)->RemoveElementAt(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
// scan for table elements. If we find table elements other than table,
|
|
|
|
// replace it with a list of any editable non-table content.
|
2000-08-14 03:53:34 +04:00
|
|
|
if (nsHTMLEditUtils::IsTableElement(testNode) && !nsHTMLEditUtils::IsTable(testNode))
|
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
|
|
|
{
|
|
|
|
(*outArrayOfNodes)->RemoveElementAt(i);
|
2000-06-02 11:47:53 +04:00
|
|
|
res = GetInnerContent(testNode, *outArrayOfNodes, PR_FALSE);
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-06-02 11:47:53 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetDefinitionListItemTypes:
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::GetDefinitionListItemTypes(nsIDOMNode *aNode, PRBool &aDT, PRBool &aDD)
|
|
|
|
{
|
|
|
|
if (!aNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
aDT = aDD = PR_FALSE;
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
nsCOMPtr<nsIDOMNode> child, temp;
|
|
|
|
res = aNode->GetFirstChild(getter_AddRefs(child));
|
|
|
|
while (child && NS_SUCCEEDED(res))
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->NodeIsType(child,nsIEditProperty::dt)) aDT = PR_TRUE;
|
|
|
|
else if (mHTMLEditor->NodeIsType(child,nsIEditProperty::dd)) aDD = PR_TRUE;
|
2000-06-02 11:47:53 +04:00
|
|
|
res = child->GetNextSibling(getter_AddRefs(temp));
|
|
|
|
child = temp;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetParagraphFormatNodes:
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::GetParagraphFormatNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
|
|
|
PRBool aDontTouchContent)
|
|
|
|
{
|
|
|
|
if (!outArrayOfNodes) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection>selection;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
|
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;
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfRanges;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetPromotedRanges(selection, address_of(arrayOfRanges), kMakeList);
|
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;
|
|
|
|
|
|
|
|
// use these ranges to contruct a list of nodes to act on.
|
|
|
|
res = GetNodesForOperation(arrayOfRanges, outArrayOfNodes, kMakeBasicBlock, aDontTouchContent);
|
2000-05-03 04:14:28 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// pre process our list of nodes...
|
|
|
|
PRUint32 listCount;
|
|
|
|
PRInt32 i;
|
|
|
|
(*outArrayOfNodes)->Count(&listCount);
|
|
|
|
for (i=(PRInt32)listCount-1; i>=0; i--)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)((*outArrayOfNodes)->ElementAt(i));
|
|
|
|
nsCOMPtr<nsIDOMNode> testNode( do_QueryInterface(isupports ) );
|
|
|
|
|
|
|
|
// Remove all non-editable nodes. Leave them be.
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!mHTMLEditor->IsEditable(testNode))
|
2000-05-03 04:14:28 +04:00
|
|
|
{
|
|
|
|
(*outArrayOfNodes)->RemoveElementAt(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
// scan for table elements. If we find table elements other than table,
|
2000-06-02 11:47:53 +04:00
|
|
|
// replace it with a list of any editable non-table content. Ditto for list elements.
|
2000-08-14 03:53:34 +04:00
|
|
|
if (nsHTMLEditUtils::IsTableElement(testNode) ||
|
2000-06-02 11:47:53 +04:00
|
|
|
nsHTMLEditUtils::IsList(testNode) ||
|
|
|
|
nsHTMLEditUtils::IsListItem(testNode) )
|
2000-06-02 10:03:46 +04:00
|
|
|
{
|
|
|
|
(*outArrayOfNodes)->RemoveElementAt(i);
|
2000-06-02 11:47:53 +04:00
|
|
|
res = GetInnerContent(testNode, *outArrayOfNodes);
|
2000-06-02 10:03:46 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
2000-05-03 04:14:28 +04:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-08-26 08:03:50 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// BustUpInlinesAtRangeEndpoints:
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::BustUpInlinesAtRangeEndpoints(nsRangeStore &item)
|
|
|
|
{
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
PRBool isCollapsed = ((item.startNode == item.endNode) && (item.startOffset == item.endOffset));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> endInline = GetHighestInlineParent(item.endNode);
|
|
|
|
|
|
|
|
// if we have inline parents above range endpoints, split them
|
|
|
|
if (endInline && !isCollapsed)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> resultEndNode;
|
|
|
|
PRInt32 resultEndOffset;
|
|
|
|
item.endNode->GetParentNode(getter_AddRefs(resultEndNode));
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SplitNodeDeep(endInline, item.endNode, item.endOffset,
|
2000-08-26 08:03:50 +04:00
|
|
|
&resultEndOffset, PR_TRUE);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// reset range
|
|
|
|
item.endNode = resultEndNode; item.endOffset = resultEndOffset;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> startInline = GetHighestInlineParent(item.startNode);
|
|
|
|
|
|
|
|
if (startInline)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> resultStartNode;
|
|
|
|
PRInt32 resultStartOffset;
|
|
|
|
item.startNode->GetParentNode(getter_AddRefs(resultStartNode));
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SplitNodeDeep(startInline, item.startNode, item.startOffset,
|
2000-08-26 08:03:50 +04:00
|
|
|
&resultStartOffset, PR_TRUE);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// reset range
|
|
|
|
item.startNode = resultStartNode; item.startOffset = resultStartOffset;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-04-24 15:51:12 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// BustUpInlinesAtBRs:
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::BustUpInlinesAtBRs(nsIDOMNode *inNode,
|
|
|
|
nsCOMPtr<nsISupportsArray> *outArrayOfNodes)
|
|
|
|
{
|
|
|
|
if (!inNode || !outArrayOfNodes) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsresult res = NS_NewISupportsArray(getter_AddRefs(*outArrayOfNodes));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// first step is to build up a list of all the break nodes inside
|
|
|
|
// the inline container.
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfBreaks;
|
2000-08-26 08:03:50 +04:00
|
|
|
nsBRNodeFunctor functor;
|
|
|
|
nsDOMIterator iter;
|
|
|
|
res = iter.Init(inNode);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = iter.MakeList(functor, address_of(arrayOfBreaks));
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2000-08-26 08:03:50 +04:00
|
|
|
// if there aren't any breaks, just put inNode itself in the array
|
|
|
|
nsCOMPtr<nsISupports> isupports;
|
2000-04-24 15:51:12 +04:00
|
|
|
PRUint32 listCount;
|
|
|
|
arrayOfBreaks->Count(&listCount);
|
|
|
|
if (!listCount)
|
|
|
|
{
|
|
|
|
isupports = do_QueryInterface(inNode);
|
|
|
|
(*outArrayOfNodes)->AppendElement(isupports);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// else we need to bust up inNode along all the breaks
|
|
|
|
nsCOMPtr<nsIDOMNode> breakNode;
|
|
|
|
nsCOMPtr<nsIDOMNode> inlineParentNode;
|
|
|
|
nsCOMPtr<nsIDOMNode> leftNode;
|
|
|
|
nsCOMPtr<nsIDOMNode> rightNode;
|
|
|
|
nsCOMPtr<nsIDOMNode> splitDeepNode = inNode;
|
|
|
|
nsCOMPtr<nsIDOMNode> splitParentNode;
|
|
|
|
PRInt32 splitOffset, resultOffset, i;
|
|
|
|
inNode->GetParentNode(getter_AddRefs(inlineParentNode));
|
|
|
|
|
2000-06-06 00:26:40 +04:00
|
|
|
for (i=0; i< (PRInt32)listCount; i++)
|
2000-04-24 15:51:12 +04:00
|
|
|
{
|
|
|
|
isupports = (dont_AddRef)(arrayOfBreaks->ElementAt(i));
|
|
|
|
breakNode = do_QueryInterface(isupports);
|
|
|
|
if (!breakNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
if (!splitDeepNode) return NS_ERROR_NULL_POINTER;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(breakNode, address_of(splitParentNode), &splitOffset);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SplitNodeDeep(splitDeepNode, splitParentNode, splitOffset,
|
2000-12-09 07:46:08 +03:00
|
|
|
&resultOffset, PR_FALSE, address_of(leftNode), address_of(rightNode));
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// put left node in node list
|
|
|
|
if (leftNode)
|
|
|
|
{
|
|
|
|
// might not be a left node. a break might have been at the very
|
|
|
|
// beginning of inline container, in which case splitnodedeep
|
|
|
|
// would not actually split anything
|
|
|
|
isupports = do_QueryInterface(leftNode);
|
|
|
|
(*outArrayOfNodes)->AppendElement(isupports);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
// move break outside of container and also put in node list
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->MoveNode(breakNode, inlineParentNode, resultOffset);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
isupports = do_QueryInterface(breakNode);
|
|
|
|
(*outArrayOfNodes)->AppendElement(isupports);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// now rightNode becomes the new node to split
|
|
|
|
splitDeepNode = rightNode;
|
|
|
|
}
|
|
|
|
// now tack on remaining rightNode, if any, to the list
|
|
|
|
if (rightNode)
|
|
|
|
{
|
|
|
|
isupports = do_QueryInterface(rightNode);
|
|
|
|
(*outArrayOfNodes)->AppendElement(isupports);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-08-26 08:03:50 +04:00
|
|
|
nsCOMPtr<nsIDOMNode>
|
|
|
|
nsHTMLEditRules::GetHighestInlineParent(nsIDOMNode* aNode)
|
|
|
|
{
|
|
|
|
if (!aNode) return nsnull;
|
|
|
|
if (nsEditor::IsBlockNode(aNode)) return nsnull;
|
|
|
|
nsCOMPtr<nsIDOMNode> inlineNode, node=aNode;
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
while (node && mHTMLEditor->IsInlineNode(node))
|
2000-08-26 08:03:50 +04:00
|
|
|
{
|
|
|
|
inlineNode = node;
|
|
|
|
inlineNode->GetParentNode(getter_AddRefs(node));
|
|
|
|
}
|
|
|
|
return inlineNode;
|
|
|
|
}
|
2000-04-24 15:51:12 +04:00
|
|
|
|
1999-07-01 17:42:03 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// MakeTransitionList: detect all the transitions in the array, where a
|
|
|
|
// transition means that adjacent nodes in the array
|
|
|
|
// don't have the same parent.
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::MakeTransitionList(nsISupportsArray *inArrayOfNodes,
|
|
|
|
nsVoidArray *inTransitionArray)
|
|
|
|
{
|
|
|
|
if (!inArrayOfNodes || !inTransitionArray) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
PRUint32 listCount;
|
2000-06-06 00:26:40 +04:00
|
|
|
PRUint32 i;
|
1999-07-01 17:42:03 +04:00
|
|
|
inArrayOfNodes->Count(&listCount);
|
|
|
|
nsVoidArray transitionList;
|
|
|
|
nsCOMPtr<nsIDOMNode> prevElementParent;
|
|
|
|
nsCOMPtr<nsIDOMNode> curElementParent;
|
|
|
|
|
2000-06-06 00:26:40 +04:00
|
|
|
for (i=0; i<listCount; i++)
|
1999-07-01 17:42:03 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(inArrayOfNodes->ElementAt(i));
|
|
|
|
nsCOMPtr<nsIDOMNode> transNode( do_QueryInterface(isupports ) );
|
|
|
|
transNode->GetParentNode(getter_AddRefs(curElementParent));
|
|
|
|
if (curElementParent != prevElementParent)
|
|
|
|
{
|
1999-08-11 01:44:10 +04:00
|
|
|
// different parents, or seperated by <br>: transition point
|
|
|
|
inTransitionArray->InsertElementAt((void*)PR_TRUE,i);
|
1999-07-01 17:42:03 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-08-11 01:44:10 +04:00
|
|
|
// same parents: these nodes grew up together
|
|
|
|
inTransitionArray->InsertElementAt((void*)PR_FALSE,i);
|
1999-07-01 17:42:03 +04:00
|
|
|
}
|
|
|
|
prevElementParent = curElementParent;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-06-25 13:33:02 +04:00
|
|
|
|
1999-04-13 17:35:08 +04:00
|
|
|
/********************************************************
|
1999-06-16 09:02:43 +04:00
|
|
|
* main implementation methods
|
1999-04-13 17:35:08 +04:00
|
|
|
********************************************************/
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// InsertTab: top level logic for determining how to insert a tab
|
|
|
|
//
|
1999-04-12 16:01:32 +04:00
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::InsertTab(nsISelection *aSelection,
|
1999-04-12 16:01:32 +04:00
|
|
|
nsString *outString)
|
|
|
|
{
|
1999-04-21 18:49:58 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> parentNode;
|
1999-04-13 17:35:08 +04:00
|
|
|
PRInt32 offset;
|
2000-01-15 17:29:29 +03:00
|
|
|
PRBool isPRE;
|
1999-04-13 17:35:08 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(parentNode), &offset);
|
1999-08-10 01:50:02 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-04-13 17:35:08 +04:00
|
|
|
|
1999-04-21 18:49:58 +04:00
|
|
|
if (!parentNode) return NS_ERROR_FAILURE;
|
1999-04-13 17:35:08 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->IsPreformatted(parentNode, &isPRE);
|
1999-08-10 01:50:02 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-04-13 17:35:08 +04:00
|
|
|
|
1999-04-12 16:01:32 +04:00
|
|
|
if (isPRE)
|
|
|
|
{
|
2000-04-18 11:52:02 +04:00
|
|
|
outString->AssignWithConversion('\t');
|
1999-04-12 16:01:32 +04:00
|
|
|
}
|
2000-01-15 17:29:29 +03:00
|
|
|
else
|
1999-04-21 18:49:58 +04:00
|
|
|
{
|
2000-01-15 17:29:29 +03:00
|
|
|
// number of spaces should be a pref?
|
|
|
|
// note that we dont play around with nbsps here anymore.
|
|
|
|
// let the AfterEdit whitespace cleanup code handle it.
|
2000-04-18 11:52:02 +04:00
|
|
|
outString->AssignWithConversion(" ");
|
1999-04-21 18:49:58 +04:00
|
|
|
}
|
1999-04-13 17:35:08 +04:00
|
|
|
|
1999-04-12 16:01:32 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-04-26 18:08:52 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// ReturnInHeader: do the right thing for returns pressed in headers
|
|
|
|
//
|
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::ReturnInHeader(nsISelection *aSelection,
|
1999-04-26 18:08:52 +04:00
|
|
|
nsIDOMNode *aHeader,
|
1999-08-18 12:13:06 +04:00
|
|
|
nsIDOMNode *aNode,
|
1999-04-26 18:08:52 +04:00
|
|
|
PRInt32 aOffset)
|
|
|
|
{
|
1999-08-18 12:13:06 +04:00
|
|
|
if (!aSelection || !aHeader || !aNode) return NS_ERROR_NULL_POINTER;
|
1999-04-26 18:08:52 +04:00
|
|
|
|
1999-08-18 12:13:06 +04:00
|
|
|
// remeber where the header is
|
|
|
|
nsCOMPtr<nsIDOMNode> headerParent;
|
|
|
|
PRInt32 offset;
|
2000-12-09 07:46:08 +03:00
|
|
|
nsresult res = nsEditor::GetNodeLocation(aHeader, address_of(headerParent), &offset);
|
1999-04-26 18:08:52 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-08-18 12:13:06 +04:00
|
|
|
|
|
|
|
// split the header
|
|
|
|
PRInt32 newOffset;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SplitNodeDeep( aHeader, aNode, aOffset, &newOffset);
|
1999-04-26 18:08:52 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-02-25 07:39:30 +03:00
|
|
|
|
|
|
|
// if the leftand heading is empty, put a mozbr in it
|
|
|
|
nsCOMPtr<nsIDOMNode> prevItem;
|
2001-01-28 23:13:07 +03:00
|
|
|
mHTMLEditor->GetPriorHTMLSibling(aHeader, address_of(prevItem));
|
2000-02-25 07:39:30 +03:00
|
|
|
if (prevItem && nsHTMLEditUtils::IsHeader(prevItem))
|
|
|
|
{
|
|
|
|
PRBool bIsEmptyNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->IsEmptyNode(prevItem, &bIsEmptyNode);
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (bIsEmptyNode)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> brNode;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = CreateMozBR(prevItem, 0, address_of(brNode));
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
1999-04-26 18:08:52 +04:00
|
|
|
|
1999-08-18 12:13:06 +04:00
|
|
|
// if the new (righthand) header node is empty, delete it
|
|
|
|
PRBool isEmpty;
|
1999-11-01 18:15:35 +03:00
|
|
|
res = IsEmptyBlock(aHeader, &isEmpty, PR_TRUE);
|
1999-04-26 18:08:52 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-08-18 12:13:06 +04:00
|
|
|
if (isEmpty)
|
1999-04-26 18:08:52 +04:00
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(aHeader);
|
1999-04-26 18:08:52 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-02-25 07:39:30 +03:00
|
|
|
// layout tells the caret to blink in a weird place
|
|
|
|
// if we dont place a break after the header.
|
|
|
|
nsCOMPtr<nsIDOMNode> sibling;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNextHTMLSibling(headerParent, offset+1, address_of(sibling));
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!sibling || !nsHTMLEditUtils::IsBreak(sibling))
|
|
|
|
{
|
2000-12-09 07:46:08 +03:00
|
|
|
res = CreateMozBR(headerParent, offset+1, address_of(sibling));
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(sibling, address_of(headerParent), &offset);
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// put selection after break
|
1999-08-18 12:13:06 +04:00
|
|
|
res = aSelection->Collapse(headerParent,offset+1);
|
1999-04-26 18:08:52 +04:00
|
|
|
}
|
2000-02-25 07:39:30 +03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// put selection at front of righthand heading
|
|
|
|
res = aSelection->Collapse(aHeader,0);
|
|
|
|
}
|
1999-04-26 18:08:52 +04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// ReturnInParagraph: do the right thing for returns pressed in paragraphs
|
|
|
|
//
|
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection,
|
2000-01-10 13:13:58 +03:00
|
|
|
nsIDOMNode *aPara,
|
1999-04-26 18:08:52 +04:00
|
|
|
nsIDOMNode *aNode,
|
|
|
|
PRInt32 aOffset,
|
1999-10-06 23:34:09 +04:00
|
|
|
PRBool *aCancel,
|
|
|
|
PRBool *aHandled)
|
1999-04-26 18:08:52 +04:00
|
|
|
{
|
2000-01-10 13:13:58 +03:00
|
|
|
if (!aSelection || !aPara || !aNode || !aCancel || !aHandled)
|
1999-10-06 23:34:09 +04:00
|
|
|
{ return NS_ERROR_NULL_POINTER; }
|
1999-04-26 18:08:52 +04:00
|
|
|
*aCancel = PR_FALSE;
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_FALSE;
|
1999-04-26 18:08:52 +04:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> sibling;
|
|
|
|
nsresult res = NS_OK;
|
1999-07-03 17:27:13 +04:00
|
|
|
|
1999-04-26 18:08:52 +04:00
|
|
|
// easy case, in a text node:
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->IsTextNode(aNode))
|
1999-04-26 18:08:52 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(aNode);
|
|
|
|
PRUint32 strLength;
|
|
|
|
res = textNode->GetLength(&strLength);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// at beginning of text node?
|
|
|
|
if (!aOffset)
|
|
|
|
{
|
|
|
|
// is there a BR prior to it?
|
2001-01-28 23:13:07 +03:00
|
|
|
mHTMLEditor->GetPriorHTMLSibling(aNode, address_of(sibling));
|
1999-04-26 18:08:52 +04:00
|
|
|
if (!sibling)
|
|
|
|
{
|
|
|
|
// no previous sib, so
|
|
|
|
// just fall out to default of inserting a BR
|
|
|
|
return res;
|
|
|
|
}
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsBreak(sibling)
|
|
|
|
&& !nsHTMLEditUtils::HasMozAttr(sibling))
|
1999-04-26 18:08:52 +04:00
|
|
|
{
|
1999-08-10 01:50:02 +04:00
|
|
|
PRInt32 newOffset;
|
1999-04-26 18:08:52 +04:00
|
|
|
*aCancel = PR_TRUE;
|
2000-01-10 13:13:58 +03:00
|
|
|
// split the paragraph
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SplitNodeDeep( aPara, aNode, aOffset, &newOffset);
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-04-26 18:08:52 +04:00
|
|
|
// get rid of the break
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(sibling);
|
1999-04-26 18:08:52 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-31 02:57:19 +04:00
|
|
|
// check both halves of para to see if we need mozBR
|
|
|
|
res = InsertMozBRIfNeeded(aPara);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetPriorHTMLSibling(aPara, address_of(sibling));
|
2000-03-31 02:57:19 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (sibling && nsHTMLEditUtils::IsParagraph(sibling))
|
|
|
|
{
|
|
|
|
res = InsertMozBRIfNeeded(sibling);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
2000-01-10 13:13:58 +03:00
|
|
|
// position selection inside right hand para
|
|
|
|
res = aSelection->Collapse(aPara,0);
|
1999-04-26 18:08:52 +04:00
|
|
|
}
|
|
|
|
// else just fall out to default of inserting a BR
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
// at end of text node?
|
1999-11-29 11:28:46 +03:00
|
|
|
if (aOffset == (PRInt32)strLength)
|
1999-04-26 18:08:52 +04:00
|
|
|
{
|
|
|
|
// is there a BR after to it?
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNextHTMLSibling(aNode, address_of(sibling));
|
1999-04-26 18:08:52 +04:00
|
|
|
if (!sibling)
|
|
|
|
{
|
|
|
|
// no next sib, so
|
|
|
|
// just fall out to default of inserting a BR
|
|
|
|
return res;
|
|
|
|
}
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsBreak(sibling)
|
|
|
|
&& !nsHTMLEditUtils::HasMozAttr(sibling))
|
1999-04-26 18:08:52 +04:00
|
|
|
{
|
1999-08-10 01:50:02 +04:00
|
|
|
PRInt32 newOffset;
|
1999-04-26 18:08:52 +04:00
|
|
|
*aCancel = PR_TRUE;
|
2000-01-10 13:13:58 +03:00
|
|
|
// split the paragraph
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SplitNodeDeep(aPara, aNode, aOffset, &newOffset);
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-04-26 18:08:52 +04:00
|
|
|
// get rid of the break
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(sibling);
|
1999-04-26 18:08:52 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-01-10 13:13:58 +03:00
|
|
|
// position selection inside right hand para
|
|
|
|
res = aSelection->Collapse(aPara,0);
|
1999-04-26 18:08:52 +04:00
|
|
|
}
|
|
|
|
// else just fall out to default of inserting a BR
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
// inside text node
|
|
|
|
// just fall out to default of inserting a BR
|
|
|
|
return res;
|
|
|
|
}
|
2000-01-10 13:13:58 +03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// not in a text node.
|
|
|
|
// is there a BR prior to it?
|
|
|
|
nsCOMPtr<nsIDOMNode> nearNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetPriorHTMLNode(aNode, aOffset, address_of(nearNode));
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-01-26 03:57:37 +03:00
|
|
|
if (!nearNode || !nsHTMLEditUtils::IsBreak(nearNode)
|
|
|
|
|| nsHTMLEditUtils::HasMozAttr(nearNode))
|
2000-01-10 13:13:58 +03:00
|
|
|
{
|
|
|
|
// is there a BR after to it?
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNextHTMLNode(aNode, aOffset, address_of(nearNode));
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-01-26 03:57:37 +03:00
|
|
|
if (!nearNode || !nsHTMLEditUtils::IsBreak(nearNode)
|
|
|
|
|| nsHTMLEditUtils::HasMozAttr(nearNode))
|
2000-01-10 13:13:58 +03:00
|
|
|
{
|
|
|
|
// just fall out to default of inserting a BR
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// else remove sibling br and split para
|
|
|
|
PRInt32 newOffset;
|
|
|
|
*aCancel = PR_TRUE;
|
|
|
|
// split the paragraph
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SplitNodeDeep( aPara, aNode, aOffset, &newOffset);
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// get rid of the break
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(nearNode);
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// selection to beginning of right hand para
|
|
|
|
aSelection->Collapse(aPara,0);
|
|
|
|
}
|
1999-04-26 18:08:52 +04:00
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// ReturnInListItem: do the right thing for returns pressed in list items
|
|
|
|
//
|
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::ReturnInListItem(nsISelection *aSelection,
|
1999-04-26 18:08:52 +04:00
|
|
|
nsIDOMNode *aListItem,
|
|
|
|
nsIDOMNode *aNode,
|
|
|
|
PRInt32 aOffset)
|
|
|
|
{
|
|
|
|
if (!aSelection || !aListItem || !aNode) return NS_ERROR_NULL_POINTER;
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection> selection(aSelection);
|
|
|
|
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
|
1999-08-18 12:13:06 +04:00
|
|
|
nsresult res = NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> listitem;
|
|
|
|
|
|
|
|
// sanity check
|
2000-01-26 03:57:37 +03:00
|
|
|
NS_PRECONDITION(PR_TRUE == nsHTMLEditUtils::IsListItem(aListItem),
|
|
|
|
"expected a list item and didnt get one");
|
1999-08-18 12:13:06 +04:00
|
|
|
|
|
|
|
// if we are in an empty listitem, then we want to pop up out of the list
|
|
|
|
PRBool isEmpty;
|
1999-11-01 18:15:35 +03:00
|
|
|
res = IsEmptyBlock(aListItem, &isEmpty, PR_TRUE, PR_FALSE);
|
1999-08-18 12:13:06 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-08-17 09:26:32 +04:00
|
|
|
if (isEmpty && mReturnInEmptyLIKillsList) // but only if prefs says it's ok
|
1999-08-18 12:13:06 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> list, listparent;
|
1999-11-25 03:19:45 +03:00
|
|
|
PRInt32 offset, itemOffset;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(aListItem, address_of(list), &itemOffset);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(list, address_of(listparent), &offset);
|
1999-08-18 12:13:06 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
// are we the last list item in the list?
|
|
|
|
PRBool bIsLast;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->IsLastEditableChild(aListItem, &bIsLast);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!bIsLast)
|
|
|
|
{
|
|
|
|
// we need to split the list!
|
|
|
|
nsCOMPtr<nsIDOMNode> tempNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SplitNode(list, itemOffset, getter_AddRefs(tempNode));
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
1999-08-18 12:13:06 +04:00
|
|
|
// are we in a sublist?
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsList(listparent)) //in a sublist
|
1999-08-18 12:13:06 +04:00
|
|
|
{
|
|
|
|
// if so, move this list item out of this list and into the grandparent list
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->MoveNode(aListItem,listparent,offset+1);
|
1999-08-18 12:13:06 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = aSelection->Collapse(aListItem,0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-02-25 07:39:30 +03:00
|
|
|
// otherwise kill this listitem
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(aListItem);
|
1999-08-18 12:13:06 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-11-25 03:19:45 +03:00
|
|
|
|
2000-02-25 07:39:30 +03:00
|
|
|
// time to insert a break
|
|
|
|
nsCOMPtr<nsIDOMNode> brNode;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = CreateMozBR(listparent, offset+1, address_of(brNode));
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-02-25 07:39:30 +03:00
|
|
|
|
|
|
|
// set selection to before the moz br
|
2000-09-14 15:45:01 +04:00
|
|
|
selPriv->SetInterlinePosition(PR_TRUE);
|
2000-02-25 07:39:30 +03:00
|
|
|
res = aSelection->Collapse(listparent,offset+1);
|
1999-11-25 03:19:45 +03:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
1999-08-18 12:13:06 +04:00
|
|
|
// else we want a new list item at the same list level
|
1999-08-10 01:50:02 +04:00
|
|
|
PRInt32 newOffset;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SplitNodeDeep( aListItem, aNode, aOffset, &newOffset);
|
1999-08-18 12:13:06 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-02-25 07:39:30 +03:00
|
|
|
// hack: until I can change the damaged doc range code back to being
|
|
|
|
// extra inclusive, I have to manually detect certain list items that
|
|
|
|
// may be left empty.
|
|
|
|
nsCOMPtr<nsIDOMNode> prevItem;
|
2001-01-28 23:13:07 +03:00
|
|
|
mHTMLEditor->GetPriorHTMLSibling(aListItem, address_of(prevItem));
|
2000-02-25 07:39:30 +03:00
|
|
|
if (prevItem && nsHTMLEditUtils::IsListItem(prevItem))
|
|
|
|
{
|
|
|
|
PRBool bIsEmptyNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->IsEmptyNode(prevItem, &bIsEmptyNode);
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (bIsEmptyNode)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> brNode;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = CreateMozBR(prevItem, 0, address_of(brNode));
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
1999-08-18 12:13:06 +04:00
|
|
|
res = aSelection->Collapse(aListItem,0);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-04-24 15:51:12 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// MakeBlockquote: put the list of nodes into one or more blockquotes.
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::MakeBlockquote(nsISupportsArray *arrayOfNodes)
|
|
|
|
{
|
|
|
|
// the idea here is to put the nodes into a minimal number of
|
|
|
|
// blockquotes. When the user blockquotes something, they expect
|
|
|
|
// one blockquote. That may not be possible (for instance, if they
|
|
|
|
// have two table cells selected, you need two blockquotes inside the cells).
|
|
|
|
|
|
|
|
if (!arrayOfNodes) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> curNode, curParent, curBlock, newBlock;
|
|
|
|
PRInt32 offset;
|
|
|
|
PRUint32 listCount;
|
|
|
|
|
|
|
|
arrayOfNodes->Count(&listCount);
|
|
|
|
nsCOMPtr<nsIDOMNode> prevParent;
|
|
|
|
|
|
|
|
PRUint32 i;
|
|
|
|
for (i=0; i<listCount; i++)
|
|
|
|
{
|
|
|
|
// get the node to act on, and it's location
|
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
|
|
|
curNode = do_QueryInterface(isupports);
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// if the node is a table element or list item, dive inside
|
2000-08-14 03:53:34 +04:00
|
|
|
if ( (nsHTMLEditUtils::IsTableElement(curNode) && !(nsHTMLEditUtils::IsTable(curNode))) ||
|
2000-04-24 15:51:12 +04:00
|
|
|
nsHTMLEditUtils::IsListItem(curNode) )
|
|
|
|
{
|
|
|
|
curBlock = 0; // forget any previous block
|
|
|
|
// recursion time
|
|
|
|
nsCOMPtr<nsISupportsArray> childArray;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetChildNodesForOperation(curNode, address_of(childArray));
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = MakeBlockquote(childArray);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the node has different parent than previous node,
|
|
|
|
// further nodes in a new parent
|
|
|
|
if (prevParent)
|
|
|
|
{
|
2000-11-30 01:06:02 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> temp;
|
|
|
|
curNode->GetParentNode(getter_AddRefs(temp));
|
|
|
|
if (temp != prevParent)
|
2000-04-24 15:51:12 +04:00
|
|
|
{
|
|
|
|
curBlock = 0; // forget any previous blockquote node we were using
|
2000-11-30 01:06:02 +03:00
|
|
|
prevParent = temp;
|
2000-04-24 15:51:12 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
curNode->GetParentNode(getter_AddRefs(prevParent));
|
|
|
|
}
|
|
|
|
|
|
|
|
// if no curBlock, make one
|
|
|
|
if (!curBlock)
|
|
|
|
{
|
|
|
|
nsAutoString quoteType; quoteType.AssignWithConversion("blockquote");
|
2000-12-09 07:46:08 +03:00
|
|
|
res = SplitAsNeeded("eType, address_of(curParent), &offset);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateNode(quoteType, curParent, offset, getter_AddRefs(curBlock));
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32 blockLen;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetLengthOfDOMNode(curBlock, blockLen);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->MoveNode(curNode, curBlock, blockLen);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
1999-08-18 12:13:06 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// ApplyBlockStyle: do whatever it takes to make the list of nodes into
|
|
|
|
// one or more blocks of type blockTag.
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString *aBlockTag)
|
|
|
|
{
|
|
|
|
// intent of this routine is to be used for converting to/from
|
1999-11-25 03:19:45 +03:00
|
|
|
// headers, paragraphs, pre, and address. Those blocks
|
1999-08-18 12:13:06 +04:00
|
|
|
// that pretty much just contain inline things...
|
|
|
|
|
|
|
|
if (!arrayOfNodes || !aBlockTag) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> curNode, curParent, curBlock, newBlock;
|
|
|
|
PRInt32 offset;
|
|
|
|
PRUint32 listCount;
|
1999-11-25 03:19:45 +03:00
|
|
|
PRBool bNoParent = PR_FALSE;
|
|
|
|
|
|
|
|
// we special case an empty tag name to mean "remove block parents".
|
|
|
|
// This is used for the "normal" paragraph style in mail-compose
|
2000-04-18 11:52:02 +04:00
|
|
|
if (aBlockTag->IsEmpty() || aBlockTag->EqualsWithConversion("normal")) bNoParent = PR_TRUE;
|
1999-11-25 03:19:45 +03:00
|
|
|
|
1999-08-18 12:13:06 +04:00
|
|
|
arrayOfNodes->Count(&listCount);
|
|
|
|
|
|
|
|
PRUint32 i;
|
|
|
|
for (i=0; i<listCount; i++)
|
|
|
|
{
|
|
|
|
// get the node to act on, and it's location
|
|
|
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
1999-09-11 04:20:59 +04:00
|
|
|
curNode = do_QueryInterface(isupports);
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
|
1999-08-18 12:13:06 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
nsAutoString curNodeTag;
|
|
|
|
nsEditor::GetTagString(curNode, curNodeTag);
|
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
|
|
|
curNodeTag.ToLowerCase();
|
1999-08-18 12:13:06 +04:00
|
|
|
|
|
|
|
// is it already the right kind of block?
|
1999-11-25 03:19:45 +03:00
|
|
|
if (!bNoParent && curNodeTag == *aBlockTag)
|
1999-08-18 12:13:06 +04:00
|
|
|
{
|
|
|
|
curBlock = 0; // forget any previous block used for previous inline nodes
|
|
|
|
continue; // do nothing to this block
|
|
|
|
}
|
|
|
|
|
1999-09-30 00:08:15 +04:00
|
|
|
// if curNode is a mozdiv, p, header, address, or pre, replace
|
1999-08-18 12:13:06 +04:00
|
|
|
// it with a new block of correct type.
|
|
|
|
// xxx floppy moose: pre cant hold everything the others can
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsMozDiv(curNode) ||
|
2000-04-18 11:52:02 +04:00
|
|
|
(curNodeTag.EqualsWithConversion("pre")) ||
|
|
|
|
(curNodeTag.EqualsWithConversion("p")) ||
|
|
|
|
(curNodeTag.EqualsWithConversion("h1")) ||
|
|
|
|
(curNodeTag.EqualsWithConversion("h2")) ||
|
|
|
|
(curNodeTag.EqualsWithConversion("h3")) ||
|
|
|
|
(curNodeTag.EqualsWithConversion("h4")) ||
|
|
|
|
(curNodeTag.EqualsWithConversion("h5")) ||
|
|
|
|
(curNodeTag.EqualsWithConversion("h6")) ||
|
|
|
|
(curNodeTag.EqualsWithConversion("address")))
|
1999-08-18 12:13:06 +04:00
|
|
|
{
|
|
|
|
curBlock = 0; // forget any previous block used for previous inline nodes
|
1999-11-25 03:19:45 +03:00
|
|
|
if (bNoParent)
|
|
|
|
{
|
2000-04-24 15:51:12 +04:00
|
|
|
// make sure we have a normal br at end of block
|
|
|
|
res = AddTerminatingBR(curNode);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->RemoveContainer(curNode);
|
1999-11-25 03:19:45 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->ReplaceContainer(curNode, address_of(newBlock), *aBlockTag);
|
1999-11-25 03:19:45 +03:00
|
|
|
}
|
1999-08-18 12:13:06 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
2000-04-18 11:52:02 +04:00
|
|
|
else if ((curNodeTag.EqualsWithConversion("table")) ||
|
|
|
|
(curNodeTag.EqualsWithConversion("tbody")) ||
|
|
|
|
(curNodeTag.EqualsWithConversion("tr")) ||
|
|
|
|
(curNodeTag.EqualsWithConversion("td")) ||
|
|
|
|
(curNodeTag.EqualsWithConversion("ol")) ||
|
|
|
|
(curNodeTag.EqualsWithConversion("ul")) ||
|
|
|
|
(curNodeTag.EqualsWithConversion("li")) ||
|
|
|
|
(curNodeTag.EqualsWithConversion("blockquote")) ||
|
|
|
|
(curNodeTag.EqualsWithConversion("div"))) // div's other than mozdivs
|
1999-08-18 12:13:06 +04:00
|
|
|
{
|
|
|
|
curBlock = 0; // forget any previous block used for previous inline nodes
|
|
|
|
// recursion time
|
|
|
|
nsCOMPtr<nsISupportsArray> childArray;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = GetChildNodesForOperation(curNode, address_of(childArray));
|
1999-08-18 12:13:06 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = ApplyBlockStyle(childArray, aBlockTag);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
// if the node is a break, we honor it by putting further nodes in a new parent
|
2000-04-18 11:52:02 +04:00
|
|
|
else if (curNodeTag.EqualsWithConversion("br"))
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
curBlock = 0; // forget any previous block used for previous inline nodes
|
|
|
|
if (!bNoParent)
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(curNode);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-08-18 12:13:06 +04:00
|
|
|
// if curNode is inline, pull it into curBlock
|
|
|
|
// note: it's assumed that consecutive inline nodes in the
|
|
|
|
// arrayOfNodes are actually members of the same block parent.
|
|
|
|
// this happens to be true now as a side effect of how
|
|
|
|
// arrayOfNodes is contructed, but some additional logic should
|
|
|
|
// be added here if that should change
|
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
else if (nsEditor::IsInlineNode(curNode) && !bNoParent)
|
1999-08-18 12:13:06 +04:00
|
|
|
{
|
|
|
|
// if curNode is a non editable, drop it if we are going to <pre>
|
2001-01-28 23:13:07 +03:00
|
|
|
if ((aBlockTag->EqualsWithConversion("pre")) && (!mHTMLEditor->IsEditable(curNode)))
|
1999-08-18 12:13:06 +04:00
|
|
|
continue; // do nothing to this block
|
|
|
|
|
|
|
|
// if no curBlock, make one
|
|
|
|
if (!curBlock)
|
|
|
|
{
|
2000-12-09 07:46:08 +03:00
|
|
|
res = SplitAsNeeded(aBlockTag, address_of(curParent), &offset);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateNode(*aBlockTag, curParent, offset, getter_AddRefs(curBlock));
|
1999-08-18 12:13:06 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if curNode is a Break, replace it with a return if we are going to <pre>
|
|
|
|
// xxx floppy moose
|
|
|
|
|
|
|
|
// this is a continuation of some inline nodes that belong together in
|
|
|
|
// the same block item. use curBlock
|
|
|
|
PRUint32 blockLen;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetLengthOfDOMNode(curBlock, blockLen);
|
1999-08-18 12:13:06 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->MoveNode(curNode, curBlock, blockLen);
|
1999-08-18 12:13:06 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-04-24 15:51:12 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// SplitAsNeeded: given a tag name, split inOutParent up to the point
|
|
|
|
// where we can insert the tag. Adjust inOutParent and
|
|
|
|
// inOutOffset to pint to new location for tag.
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::SplitAsNeeded(const nsString *aTag,
|
|
|
|
nsCOMPtr<nsIDOMNode> *inOutParent,
|
|
|
|
PRInt32 *inOutOffset)
|
|
|
|
{
|
|
|
|
if (!aTag || !inOutParent || !inOutOffset) return NS_ERROR_NULL_POINTER;
|
|
|
|
if (!*inOutParent) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsCOMPtr<nsIDOMNode> tagParent, temp, splitNode, parent = *inOutParent;
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
|
|
|
|
// check that we have a place that can legally contain the tag
|
|
|
|
while (!tagParent)
|
|
|
|
{
|
|
|
|
// sniffing up the parent tree until we find
|
|
|
|
// a legal place for the block
|
|
|
|
if (!parent) break;
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->CanContainTag(parent, *aTag))
|
2000-04-24 15:51:12 +04:00
|
|
|
{
|
|
|
|
tagParent = parent;
|
2000-05-03 04:14:28 +04:00
|
|
|
break;
|
2000-04-24 15:51:12 +04:00
|
|
|
}
|
|
|
|
splitNode = parent;
|
|
|
|
parent->GetParentNode(getter_AddRefs(temp));
|
|
|
|
parent = temp;
|
|
|
|
}
|
|
|
|
if (!tagParent)
|
|
|
|
{
|
|
|
|
// could not find a place to build tag!
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2000-05-03 04:14:28 +04:00
|
|
|
if (splitNode)
|
2000-04-24 15:51:12 +04:00
|
|
|
{
|
2000-05-03 04:14:28 +04:00
|
|
|
// we found a place for block, but above inOutParent. We need to split nodes.
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SplitNodeDeep(splitNode, *inOutParent, *inOutOffset, inOutOffset);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
*inOutParent = tagParent;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// AddTerminatingBR: place an ordinary br node at the end of aBlock,
|
|
|
|
// if it doens't already have one. If it has a moz-BR,
|
|
|
|
// simply convertit to a normal br.
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::AddTerminatingBR(nsIDOMNode *aBlock)
|
|
|
|
{
|
|
|
|
if (!aBlock) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsCOMPtr<nsIDOMNode> last;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res = mHTMLEditor->GetLastEditableLeaf(aBlock, address_of(last));
|
2000-04-24 15:51:12 +04:00
|
|
|
if (last && nsHTMLEditUtils::IsBreak(last))
|
|
|
|
{
|
|
|
|
if (nsHTMLEditUtils::IsMozBR(last))
|
|
|
|
{
|
|
|
|
// need to convert a br
|
|
|
|
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(last);
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->RemoveAttribute(elem, NS_ConvertASCIItoUCS2("type"));
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
else // we have what we want, we're done
|
|
|
|
{
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else // need to add a br
|
|
|
|
{
|
|
|
|
PRUint32 len;
|
|
|
|
nsCOMPtr<nsIDOMNode> brNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetLengthOfDOMNode(aBlock, len);
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateBR(aBlock, len, address_of(brNode));
|
2000-04-24 15:51:12 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
1999-09-02 01:23:47 +04:00
|
|
|
|
|
|
|
|
1999-09-06 23:51:59 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// JoinNodesSmart: join two nodes, doing whatever makes sense for their
|
|
|
|
// children (which often means joining them, too).
|
|
|
|
// aNodeLeft & aNodeRight must be same type of node.
|
1999-09-02 01:23:47 +04:00
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::JoinNodesSmart( nsIDOMNode *aNodeLeft,
|
|
|
|
nsIDOMNode *aNodeRight,
|
|
|
|
nsCOMPtr<nsIDOMNode> *aOutMergeParent,
|
|
|
|
PRInt32 *aOutMergeOffset)
|
|
|
|
{
|
|
|
|
// check parms
|
|
|
|
if (!aNodeLeft ||
|
|
|
|
!aNodeRight ||
|
|
|
|
!aOutMergeParent ||
|
|
|
|
!aOutMergeOffset)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
// caller responsible for:
|
1999-09-06 23:51:59 +04:00
|
|
|
// left & right node are same type
|
1999-09-30 00:08:15 +04:00
|
|
|
PRInt32 parOffset;
|
|
|
|
nsCOMPtr<nsIDOMNode> parent, rightParent;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(aNodeLeft, address_of(parent), &parOffset);
|
1999-09-30 00:08:15 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
aNodeRight->GetParentNode(getter_AddRefs(rightParent));
|
|
|
|
|
|
|
|
// if they don't have the same parent, first move the 'right' node
|
|
|
|
// to after the 'left' one
|
|
|
|
if (parent != rightParent)
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->MoveNode(aNodeRight, parent, parOffset);
|
1999-09-30 00:08:15 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
1999-09-02 01:23:47 +04:00
|
|
|
|
|
|
|
// defaults for outParams
|
|
|
|
*aOutMergeParent = aNodeRight;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetLengthOfDOMNode(aNodeLeft, *((PRUint32*)aOutMergeOffset));
|
1999-09-02 01:23:47 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// seperate join rules for differing blocks
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsParagraph(aNodeLeft))
|
1999-09-02 01:23:47 +04:00
|
|
|
{
|
|
|
|
// for para's, merge deep & add a <br> after merging
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->JoinNodeDeep(aNodeLeft, aNodeRight, aOutMergeParent, aOutMergeOffset);
|
1999-09-02 01:23:47 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-11-25 03:19:45 +03:00
|
|
|
// now we need to insert a br.
|
1999-09-02 01:23:47 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> brNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateBR(*aOutMergeParent, *aOutMergeOffset, address_of(brNode));
|
1999-12-07 11:30:19 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = nsEditor::GetNodeLocation(brNode, aOutMergeParent, aOutMergeOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
(*aOutMergeOffset)++;
|
1999-09-02 01:23:47 +04:00
|
|
|
return res;
|
|
|
|
}
|
2000-01-26 03:57:37 +03:00
|
|
|
else if (nsHTMLEditUtils::IsList(aNodeLeft)
|
2001-01-28 23:13:07 +03:00
|
|
|
|| mHTMLEditor->IsTextNode(aNodeLeft))
|
1999-09-02 01:23:47 +04:00
|
|
|
{
|
|
|
|
// for list's, merge shallow (wouldn't want to combine list items)
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->JoinNodes(aNodeLeft, aNodeRight, parent);
|
1999-09-02 01:23:47 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-09-30 00:08:15 +04:00
|
|
|
// remember the last left child, and firt right child
|
|
|
|
nsCOMPtr<nsIDOMNode> lastLeft, firstRight;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetLastEditableChild(aNodeLeft, address_of(lastLeft));
|
1999-09-30 00:08:15 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetFirstEditableChild(aNodeRight, address_of(firstRight));
|
1999-09-30 00:08:15 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
1999-09-02 01:23:47 +04:00
|
|
|
// for list items, divs, etc, merge smart
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->JoinNodes(aNodeLeft, aNodeRight, parent);
|
1999-09-02 01:23:47 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-09-30 00:08:15 +04:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
if (lastLeft && firstRight && mHTMLEditor->NodesSameType(lastLeft, firstRight))
|
1999-09-30 00:08:15 +04:00
|
|
|
{
|
|
|
|
return JoinNodesSmart(lastLeft, firstRight, aOutMergeParent, aOutMergeOffset);
|
|
|
|
}
|
1999-09-02 01:23:47 +04:00
|
|
|
}
|
1999-09-30 00:08:15 +04:00
|
|
|
return res;
|
1999-09-03 14:43:00 +04:00
|
|
|
}
|
1999-09-06 23:51:59 +04:00
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
2001-01-28 23:13:07 +03:00
|
|
|
nsHTMLEditRules::GetTopEnclosingMailCite(nsIDOMNode *aNode,
|
|
|
|
nsCOMPtr<nsIDOMNode> *aOutCiteNode,
|
|
|
|
PRBool aPlainText)
|
1999-09-06 23:51:59 +04:00
|
|
|
{
|
|
|
|
// check parms
|
|
|
|
if (!aNode || !aOutCiteNode)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
nsCOMPtr<nsIDOMNode> node, parentNode;
|
|
|
|
node = do_QueryInterface(aNode);
|
|
|
|
|
|
|
|
while (node)
|
|
|
|
{
|
2001-01-28 23:13:07 +03:00
|
|
|
if ( (aPlainText && nsHTMLEditUtils::IsPre(node)) ||
|
|
|
|
(!aPlainText && nsHTMLEditUtils::IsMailCite(node)) )
|
|
|
|
*aOutCiteNode = node;
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nsHTMLEditUtils::IsBody(node)) break;
|
1999-09-06 23:51:59 +04:00
|
|
|
|
|
|
|
res = node->GetParentNode(getter_AddRefs(parentNode));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
node = parentNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
2000-07-27 05:03:16 +04:00
|
|
|
nsHTMLEditRules::AdjustSpecialBreaks(PRBool aSafeToAskFrames)
|
1999-09-06 23:51:59 +04:00
|
|
|
{
|
1999-11-25 03:19:45 +03:00
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
|
|
|
nsCOMPtr<nsISupports> isupports;
|
|
|
|
PRUint32 nodeCount,j;
|
1999-09-06 23:51:59 +04:00
|
|
|
|
2000-08-26 08:03:50 +04:00
|
|
|
// gather list of empty nodes
|
2001-01-28 23:13:07 +03:00
|
|
|
nsEmptyFunctor functor(mHTMLEditor);
|
2000-08-26 08:03:50 +04:00
|
|
|
nsDOMIterator iter;
|
|
|
|
nsresult res = iter.Init(mDocChangeRange);
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = iter.MakeList(functor, address_of(arrayOfNodes));
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-08-26 08:03:50 +04:00
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
// put moz-br's into these empty li's and td's
|
|
|
|
res = arrayOfNodes->Count(&nodeCount);
|
|
|
|
if (NS_FAILED(res)) return res;
|
1999-11-29 11:28:46 +03:00
|
|
|
for (j = 0; j < nodeCount; j++)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
|
|
|
|
nsCOMPtr<nsIDOMNode> brNode, theNode( do_QueryInterface(isupports ) );
|
|
|
|
arrayOfNodes->RemoveElementAt(0);
|
2000-12-09 07:46:08 +03:00
|
|
|
res = CreateMozBR(theNode, 0, address_of(brNode));
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::AdjustWhitespace(nsISelection *aSelection)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
|
|
|
nsCOMPtr<nsISupports> isupports;
|
|
|
|
PRUint32 nodeCount,j;
|
|
|
|
nsresult res;
|
1999-12-01 00:58:37 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
|
1999-11-25 03:19:45 +03:00
|
|
|
|
|
|
|
// special case for mDocChangeRange entirely in one text node.
|
|
|
|
// This is an efficiency hack for normal typing in the editor.
|
|
|
|
nsCOMPtr<nsIDOMNode> startNode, endNode;
|
|
|
|
PRInt32 startOffset, endOffset;
|
2000-08-24 07:54:30 +04:00
|
|
|
res = mDocChangeRange->GetStartContainer(getter_AddRefs(startNode));
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = mDocChangeRange->GetStartOffset(&startOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-08-24 07:54:30 +04:00
|
|
|
res = mDocChangeRange->GetEndContainer(getter_AddRefs(endNode));
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = mDocChangeRange->GetEndOffset(&endOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
1999-09-06 23:51:59 +04:00
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
if (startNode == endNode)
|
1999-09-06 23:51:59 +04:00
|
|
|
{
|
1999-11-25 03:19:45 +03:00
|
|
|
nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(startNode);
|
|
|
|
if (nodeAsText)
|
|
|
|
{
|
|
|
|
res = DoTextNodeWhitespace(nodeAsText, startOffset, endOffset);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-08-26 08:03:50 +04:00
|
|
|
// gather up a list of text nodes
|
2001-01-28 23:13:07 +03:00
|
|
|
nsEditableTextFunctor functor(mHTMLEditor);
|
2000-08-26 08:03:50 +04:00
|
|
|
nsDOMIterator iter;
|
|
|
|
res = iter.Init(mDocChangeRange);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = iter.MakeList(functor, address_of(arrayOfNodes));
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// now adjust whitespace on node we found
|
|
|
|
res = arrayOfNodes->Count(&nodeCount);
|
|
|
|
if (NS_FAILED(res)) return res;
|
1999-11-29 11:28:46 +03:00
|
|
|
for (j = 0; j < nodeCount; j++)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
|
|
|
|
nsCOMPtr<nsIDOMCharacterData> textNode( do_QueryInterface(isupports ) );
|
|
|
|
arrayOfNodes->RemoveElementAt(0);
|
|
|
|
res = DoTextNodeWhitespace(textNode, -1, -1);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection aAction)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
if (!aSelection) return NS_ERROR_NULL_POINTER;
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection> selection(aSelection);
|
|
|
|
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
|
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
// if the selection isn't collapsed, do nothing.
|
2000-01-10 13:13:58 +03:00
|
|
|
// moose: one thing to do instead is check for the case of
|
1999-11-25 03:19:45 +03:00
|
|
|
// only a single break selected, and collapse it. Good thing? Beats me.
|
|
|
|
PRBool bCollapsed;
|
|
|
|
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!bCollapsed) return res;
|
|
|
|
|
|
|
|
// get the (collapsed) selection location
|
2000-01-10 13:13:58 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> selNode, temp;
|
1999-11-25 03:19:45 +03:00
|
|
|
PRInt32 selOffset;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-01-10 13:13:58 +03:00
|
|
|
temp = selNode;
|
|
|
|
|
|
|
|
// are we in an editable node?
|
2001-01-28 23:13:07 +03:00
|
|
|
while (!mHTMLEditor->IsEditable(selNode))
|
2000-01-10 13:13:58 +03:00
|
|
|
{
|
|
|
|
// scan up the tree until we find an editable place to be
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(temp, address_of(selNode), &selOffset);
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!selNode) return NS_ERROR_FAILURE;
|
|
|
|
temp = selNode;
|
|
|
|
}
|
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
// are we in a text node?
|
|
|
|
nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(selNode);
|
2000-01-10 13:13:58 +03:00
|
|
|
if (textNode)
|
|
|
|
return NS_OK; // we LIKE it when we are in a text node. that RULZ
|
1999-11-25 03:19:45 +03:00
|
|
|
|
|
|
|
// do we need to insert a special mozBR? We do if we are:
|
2000-03-24 03:26:47 +03:00
|
|
|
// 1) that block is same block where selection is AND
|
|
|
|
// 2) in a collapsed selection AND
|
|
|
|
// 3) after a normal (non-moz) br AND
|
|
|
|
// 4) that br is the last editable node in it's block
|
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> nearNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, address_of(nearNode));
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
if (!nearNode) return res;
|
|
|
|
|
|
|
|
// is nearNode also a descendant of same block?
|
|
|
|
nsCOMPtr<nsIDOMNode> block, nearBlock;
|
2001-01-28 23:13:07 +03:00
|
|
|
if (mHTMLEditor->IsBlockNode(selNode)) block = selNode;
|
|
|
|
else block = mHTMLEditor->GetBlockNodeParent(selNode);
|
|
|
|
nearBlock = mHTMLEditor->GetBlockNodeParent(nearNode);
|
2000-03-24 03:26:47 +03:00
|
|
|
if (block == nearBlock)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
if (nearNode && nsHTMLEditUtils::IsBreak(nearNode)
|
|
|
|
&& !nsHTMLEditUtils::IsMozBR(nearNode))
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
PRBool bIsLast;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->IsLastEditableChild(nearNode, &bIsLast);
|
2000-03-24 03:26:47 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (bIsLast)
|
1999-09-06 23:51:59 +04:00
|
|
|
{
|
1999-11-25 03:19:45 +03:00
|
|
|
// need to insert special moz BR. Why? Because if we don't
|
|
|
|
// the user will see no new line for the break. Also, things
|
|
|
|
// like table cells won't grow in height.
|
|
|
|
nsCOMPtr<nsIDOMNode> brNode;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = CreateMozBR(selNode, selOffset, address_of(brNode));
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(brNode, address_of(selNode), &selOffset);
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-02-25 07:39:30 +03:00
|
|
|
// selection stays *before* moz-br, sticking to it
|
2000-09-14 15:45:01 +04:00
|
|
|
selPriv->SetInterlinePosition(PR_TRUE);
|
2000-02-25 07:39:30 +03:00
|
|
|
res = aSelection->Collapse(selNode,selOffset);
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-09-06 23:51:59 +04:00
|
|
|
}
|
2000-03-24 03:26:47 +03:00
|
|
|
else
|
2000-01-10 13:13:58 +03:00
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
// ok, the br inst the last child.
|
|
|
|
// the br might be right in front of a new block (ie,:
|
|
|
|
// <body> text<br> <ol><li>list item</li></ol></body> )
|
|
|
|
// in this case we also need moz-br.
|
|
|
|
nsCOMPtr<nsIDOMNode> nextNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNextHTMLNode(nearNode, address_of(nextNode));
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNextHTMLSibling(nearNode, address_of(nextNode));
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
if (nextNode && mHTMLEditor->IsBlockNode(nextNode))
|
2000-03-24 03:26:47 +03:00
|
|
|
{
|
|
|
|
// need to insert special moz BR. Why? Because if we don't
|
|
|
|
// the user will see no new line for the break.
|
|
|
|
nsCOMPtr<nsIDOMNode> brNode;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = CreateMozBR(selNode, selOffset, address_of(brNode));
|
2000-03-24 03:26:47 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(brNode, address_of(selNode), &selOffset);
|
2000-03-24 03:26:47 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// selection stays *before* moz-br, sticking to it
|
2000-09-14 15:45:01 +04:00
|
|
|
selPriv->SetInterlinePosition(PR_TRUE);
|
2000-03-24 03:26:47 +03:00
|
|
|
res = aSelection->Collapse(selNode,selOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
2000-01-10 13:13:58 +03:00
|
|
|
}
|
1999-11-25 03:19:45 +03:00
|
|
|
}
|
|
|
|
}
|
2000-02-17 22:40:18 +03:00
|
|
|
|
2000-01-17 15:41:34 +03:00
|
|
|
// we aren't in a textnode: are we adjacent to a break or an image?
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetPriorHTMLSibling(selNode, selOffset, address_of(nearNode));
|
2000-01-17 15:41:34 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nearNode && (nsHTMLEditUtils::IsBreak(nearNode)
|
|
|
|
|| nsHTMLEditUtils::IsImage(nearNode)))
|
2000-01-17 15:41:34 +03:00
|
|
|
return NS_OK; // this is a good place for the caret to be
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNextHTMLSibling(selNode, selOffset, address_of(nearNode));
|
2000-01-17 15:41:34 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nearNode && (nsHTMLEditUtils::IsBreak(nearNode)
|
|
|
|
|| nsHTMLEditUtils::IsImage(nearNode)))
|
2000-01-17 15:41:34 +03:00
|
|
|
return NS_OK; // this is a good place for the caret to be
|
|
|
|
|
|
|
|
// look for a nearby text node.
|
1999-12-07 11:30:19 +03:00
|
|
|
// prefer the correct direction.
|
2000-12-09 07:46:08 +03:00
|
|
|
res = FindNearSelectableNode(selNode, selOffset, aAction, address_of(nearNode));
|
1999-12-07 11:30:19 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-01-17 15:41:34 +03:00
|
|
|
|
|
|
|
if (!nearNode) return NS_OK; // couldn't find a near text node
|
|
|
|
|
|
|
|
// is the nearnode a text node?
|
|
|
|
textNode = do_QueryInterface(nearNode);
|
|
|
|
if (textNode)
|
1999-12-07 11:30:19 +03:00
|
|
|
{
|
2000-01-17 15:41:34 +03:00
|
|
|
PRInt32 offset = 0;
|
|
|
|
// put selection in right place:
|
|
|
|
if (aAction == nsIEditor::ePrevious)
|
|
|
|
textNode->GetLength((PRUint32*)&offset);
|
|
|
|
res = aSelection->Collapse(nearNode,offset);
|
1999-12-07 11:30:19 +03:00
|
|
|
}
|
2000-01-17 15:41:34 +03:00
|
|
|
else // must be break or image
|
1999-12-07 11:30:19 +03:00
|
|
|
{
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(nearNode, address_of(selNode), &selOffset);
|
2000-01-17 15:41:34 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (aAction == nsIEditor::ePrevious) selOffset++; // want to be beyond it if we backed up to it
|
|
|
|
res = aSelection->Collapse(selNode, selOffset);
|
1999-12-07 11:30:19 +03:00
|
|
|
}
|
2000-02-17 22:40:18 +03:00
|
|
|
|
1999-12-07 11:30:19 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2000-01-17 15:41:34 +03:00
|
|
|
nsHTMLEditRules::FindNearSelectableNode(nsIDOMNode *aSelNode,
|
|
|
|
PRInt32 aSelOffset,
|
|
|
|
nsIEditor::EDirection aDirection,
|
|
|
|
nsCOMPtr<nsIDOMNode> *outSelectableNode)
|
1999-12-07 11:30:19 +03:00
|
|
|
{
|
2000-01-17 15:41:34 +03:00
|
|
|
if (!aSelNode || !outSelectableNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
*outSelectableNode = nsnull;
|
1999-12-07 11:30:19 +03:00
|
|
|
nsresult res = NS_OK;
|
|
|
|
|
2000-01-17 15:41:34 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> nearNode, curNode;
|
1999-12-07 11:30:19 +03:00
|
|
|
if (aDirection == nsIEditor::ePrevious)
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset, address_of(nearNode));
|
1999-12-07 11:30:19 +03:00
|
|
|
else
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNextHTMLNode(aSelNode, aSelOffset, address_of(nearNode));
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-01-17 15:41:34 +03:00
|
|
|
|
|
|
|
// scan in the right direction until we find an eligible text node,
|
|
|
|
// but dont cross any breaks, images, or table elements.
|
2001-01-28 23:13:07 +03:00
|
|
|
while (nearNode && !(mHTMLEditor->IsTextNode(nearNode)
|
2000-01-26 03:57:37 +03:00
|
|
|
|| nsHTMLEditUtils::IsBreak(nearNode)
|
|
|
|
|| nsHTMLEditUtils::IsImage(nearNode)))
|
2000-01-17 15:41:34 +03:00
|
|
|
{
|
|
|
|
curNode = nearNode;
|
|
|
|
if (aDirection == nsIEditor::ePrevious)
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetPriorHTMLNode(curNode, address_of(nearNode));
|
2000-01-17 15:41:34 +03:00
|
|
|
else
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetNextHTMLNode(curNode, address_of(nearNode));
|
2000-01-17 15:41:34 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
2000-05-05 03:54:00 +04:00
|
|
|
if (nearNode)
|
|
|
|
{
|
|
|
|
// dont cross any table elements
|
|
|
|
PRBool bInDifTblElems;
|
|
|
|
res = InDifferentTableElements(nearNode, aSelNode, &bInDifTblElems);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (bInDifTblElems) return NS_OK;
|
|
|
|
|
|
|
|
// otherwise, ok, we have found a good spot to put the selection
|
|
|
|
*outSelectableNode = do_QueryInterface(nearNode);
|
|
|
|
}
|
1999-11-25 03:19:45 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-05-05 03:54:00 +04:00
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::InDifferentTableElements(nsIDOMNode *aNode1, nsIDOMNode *aNode2, PRBool *aResult)
|
|
|
|
{
|
2001-01-17 23:01:11 +03:00
|
|
|
NS_ASSERTION(aNode1 && aNode2 && aResult, "null args");
|
2000-11-16 05:13:30 +03:00
|
|
|
if (!aNode1 || !aNode2 || !aResult) return NS_ERROR_NULL_POINTER;
|
2000-05-05 03:54:00 +04:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> tn1, tn2, node = aNode1, temp;
|
|
|
|
|
2000-08-14 03:53:34 +04:00
|
|
|
while (node && !nsHTMLEditUtils::IsTableElement(node))
|
2000-05-05 03:54:00 +04:00
|
|
|
{
|
|
|
|
node->GetParentNode(getter_AddRefs(temp));
|
|
|
|
node = temp;
|
|
|
|
}
|
|
|
|
tn1 = node;
|
|
|
|
|
|
|
|
node = aNode2;
|
2000-08-14 03:53:34 +04:00
|
|
|
while (node && !nsHTMLEditUtils::IsTableElement(node))
|
2000-05-05 03:54:00 +04:00
|
|
|
{
|
|
|
|
node->GetParentNode(getter_AddRefs(temp));
|
|
|
|
node = temp;
|
|
|
|
}
|
|
|
|
tn2 = node;
|
|
|
|
|
|
|
|
*aResult = (tn1 != tn2);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::RemoveEmptyNodes()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContentIterator> iter;
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
|
|
|
nsCOMPtr<nsISupports> isupports;
|
|
|
|
PRUint32 nodeCount,j;
|
|
|
|
|
|
|
|
// make an isupportsArray to hold a list of nodes
|
|
|
|
nsresult res = NS_NewISupportsArray(getter_AddRefs(arrayOfNodes));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// need an iterator
|
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
|
|
|
iter = do_CreateInstance(kContentIteratorCID);
|
|
|
|
if (!iter) return NS_ERROR_NULL_POINTER;
|
1999-11-25 03:19:45 +03:00
|
|
|
|
|
|
|
// loop over iter and create list of empty containers
|
|
|
|
do
|
|
|
|
{
|
|
|
|
res = iter->Init(mDocChangeRange);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// gather up a list of empty nodes
|
|
|
|
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;
|
1999-09-06 23:51:59 +04:00
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
PRBool bIsEmptyNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->IsEmptyNode(node, &bIsEmptyNode, PR_FALSE, PR_TRUE);
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-01-26 03:57:37 +03:00
|
|
|
if (bIsEmptyNode && !nsHTMLEditUtils::IsBody(node))
|
1999-09-06 23:51:59 +04:00
|
|
|
{
|
2000-02-25 07:39:30 +03:00
|
|
|
if (nsHTMLEditUtils::IsParagraph(node) ||
|
|
|
|
nsHTMLEditUtils::IsHeader(node) ||
|
|
|
|
nsHTMLEditUtils::IsListItem(node) ||
|
|
|
|
nsHTMLEditUtils::IsBlockquote(node)||
|
|
|
|
nsHTMLEditUtils::IsPre(node) ||
|
|
|
|
nsHTMLEditUtils::IsAddress(node) )
|
|
|
|
{
|
|
|
|
// if it is one of these, dont delete if sel inside.
|
|
|
|
// this is so we can create empty headings, etc, for the
|
|
|
|
// user to type into.
|
|
|
|
PRBool bIsSelInNode;
|
|
|
|
res = SelectionEndpointInNode(node, &bIsSelInNode);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!bIsSelInNode)
|
|
|
|
{
|
|
|
|
isupports = do_QueryInterface(node);
|
|
|
|
arrayOfNodes->AppendElement(isupports);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// if it's not such an element, delete it even if sel is inside
|
|
|
|
isupports = do_QueryInterface(node);
|
|
|
|
arrayOfNodes->AppendElement(isupports);
|
|
|
|
}
|
1999-09-06 23:51:59 +04:00
|
|
|
}
|
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
res = iter->Next();
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
// now delete the empty nodes
|
|
|
|
res = arrayOfNodes->Count(&nodeCount);
|
|
|
|
if (NS_FAILED(res)) return res;
|
1999-11-29 11:28:46 +03:00
|
|
|
for (j = 0; j < nodeCount; j++)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
|
|
|
|
nsCOMPtr<nsIDOMNode> delNode( do_QueryInterface(isupports ) );
|
|
|
|
arrayOfNodes->RemoveElementAt(0);
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->DeleteNode(delNode);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
} while (nodeCount); // if we deleted any, loop again
|
|
|
|
// deleting some nodes may make some parents now empty
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2000-02-25 07:39:30 +03:00
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::SelectionEndpointInNode(nsIDOMNode *aNode, PRBool *aResult)
|
|
|
|
{
|
|
|
|
if (!aNode || !aResult) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
*aResult = PR_FALSE;
|
|
|
|
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection>selection;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelectionPrivate>selPriv(do_QueryInterface(selection));
|
2000-02-25 07:39:30 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsIEnumerator> enumerator;
|
2000-09-14 15:45:01 +04:00
|
|
|
res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!enumerator) return NS_ERROR_UNEXPECTED;
|
|
|
|
|
|
|
|
for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next())
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupports> currentItem;
|
|
|
|
res = enumerator->CurrentItem(getter_AddRefs(currentItem));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!currentItem) return NS_ERROR_UNEXPECTED;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
|
|
|
|
nsCOMPtr<nsIDOMNode> startParent, endParent;
|
2000-08-24 07:54:30 +04:00
|
|
|
range->GetStartContainer(getter_AddRefs(startParent));
|
2000-02-25 07:39:30 +03:00
|
|
|
if (startParent)
|
|
|
|
{
|
|
|
|
if (aNode == startParent.get())
|
|
|
|
{
|
|
|
|
*aResult = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
if (nsHTMLEditUtils::IsDescendantOf(startParent, aNode))
|
|
|
|
{
|
|
|
|
*aResult = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
2000-08-24 07:54:30 +04:00
|
|
|
range->GetEndContainer(getter_AddRefs(endParent));
|
2000-02-25 07:39:30 +03:00
|
|
|
if (startParent == endParent) continue;
|
|
|
|
if (endParent)
|
|
|
|
{
|
|
|
|
if (aNode == endParent.get())
|
|
|
|
{
|
|
|
|
*aResult = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
if (nsHTMLEditUtils::IsDescendantOf(endParent, aNode))
|
|
|
|
{
|
|
|
|
*aResult = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::DoTextNodeWhitespace(nsIDOMCharacterData *aTextNode, PRInt32 aStart, PRInt32 aEnd)
|
|
|
|
{
|
|
|
|
// check parms
|
|
|
|
if (!aTextNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
if (aStart == -1) // -1 means do the whole darn node please
|
|
|
|
{
|
|
|
|
aStart = 0;
|
|
|
|
aTextNode->GetLength((PRUint32*)&aEnd);
|
1999-09-06 23:51:59 +04:00
|
|
|
}
|
1999-11-25 03:19:45 +03:00
|
|
|
if (aStart == aEnd) return NS_OK;
|
|
|
|
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
PRBool isPRE;
|
|
|
|
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aTextNode);
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->IsPreformatted(node,&isPRE);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
if (isPRE)
|
|
|
|
{
|
|
|
|
// text node has a Preformatted style. All we need to do is strip out any nbsp's
|
|
|
|
// we just put in and replace them with spaces.
|
|
|
|
|
|
|
|
// moose: write me!
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
// else we are not preformatted. Need to convert any adjacent spaces to alterating
|
|
|
|
// space/nbsp pairs; need to convert stranded nbsp's to spaces; need to convert
|
|
|
|
// tabs to whitespace; need to convert returns to whitespace.
|
|
|
|
PRInt32 j = 0;
|
|
|
|
nsAutoString tempString;
|
|
|
|
|
|
|
|
aTextNode->SubstringData(aStart, aEnd, tempString);
|
|
|
|
|
|
|
|
// identify runs of whitespace
|
|
|
|
PRInt32 runStart = -1, runEnd = -1;
|
|
|
|
do {
|
|
|
|
PRUnichar c = tempString[j];
|
2000-03-12 14:10:07 +03:00
|
|
|
PRBool isSpace = nsCRT::IsAsciiSpace(c);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (isSpace || c==nbsp)
|
|
|
|
{
|
|
|
|
if (runStart<0) runStart = j;
|
|
|
|
runEnd = j+1;
|
|
|
|
}
|
|
|
|
// translation of below line:
|
|
|
|
// if we have a whitespace run, AND
|
|
|
|
// either we are at the end of it, or the end of the whole string,
|
|
|
|
// THEN process it
|
|
|
|
if (runStart>=0 && (!(isSpace || c==nbsp) || (j==aEnd-1)) )
|
|
|
|
{
|
|
|
|
// current char is non whitespace, but we have identified an earlier
|
|
|
|
// run of whitespace. convert it if needed.
|
|
|
|
NS_PRECONDITION(runEnd>runStart, "this is what happens when integers turn bad!");
|
|
|
|
// runStart to runEnd is a run of whitespace
|
|
|
|
nsAutoString runStr, newStr;
|
|
|
|
tempString.Mid(runStr, runStart, runEnd-runStart);
|
2000-03-24 03:26:47 +03:00
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
res = ConvertWhitespace(runStr, newStr);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
if (runStr != newStr)
|
|
|
|
{
|
|
|
|
// delete the original whitespace run
|
2000-01-10 13:13:58 +03:00
|
|
|
EditTxn *txn;
|
1999-11-25 03:19:45 +03:00
|
|
|
// note 1: we are not telling edit listeners about these because they don't care
|
|
|
|
// note 2: we are not wrapping these in a placeholder because we know they already are
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateTxnForDeleteText(aTextNode, aStart+runStart, runEnd-runStart, (DeleteTextTxn**)&txn);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-01-10 13:13:58 +03:00
|
|
|
if (!txn) return NS_ERROR_OUT_OF_MEMORY;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->Do(txn);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// The transaction system (if any) has taken ownwership of txn
|
|
|
|
NS_IF_RELEASE(txn);
|
|
|
|
|
|
|
|
// insert the new run
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->CreateTxnForInsertText(newStr, aTextNode, aStart+runStart, (InsertTextTxn**)&txn);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-01-10 13:13:58 +03:00
|
|
|
if (!txn) return NS_ERROR_OUT_OF_MEMORY;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->Do(txn);
|
1999-11-25 03:19:45 +03:00
|
|
|
// The transaction system (if any) has taken ownwership of txns.
|
|
|
|
NS_IF_RELEASE(txn);
|
|
|
|
}
|
|
|
|
runStart = -1; // reset our run
|
|
|
|
}
|
|
|
|
j++; // next char please!
|
2000-11-17 03:25:31 +03:00
|
|
|
} while ((PRUint32)j < tempString.Length());
|
1999-11-25 03:19:45 +03:00
|
|
|
|
1999-09-06 23:51:59 +04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
nsresult
|
1999-11-25 03:36:34 +03:00
|
|
|
nsHTMLEditRules::ConvertWhitespace(const nsString & inString, nsString & outString)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
PRUint32 j,len = inString.Length();
|
|
|
|
switch (len)
|
|
|
|
{
|
|
|
|
case 0:
|
2000-04-18 11:52:02 +04:00
|
|
|
outString.SetLength(0);
|
1999-11-25 03:19:45 +03:00
|
|
|
return NS_OK;
|
|
|
|
case 1:
|
2000-04-18 11:52:02 +04:00
|
|
|
if (inString.EqualsWithConversion("\n")) // a bit of a hack: don't convert single newlines that
|
|
|
|
outString.AssignWithConversion("\n"); // dont have whitespace adjacent. This is to preserve
|
2000-03-24 03:26:47 +03:00
|
|
|
else // html source formatting to some degree.
|
2000-04-18 11:52:02 +04:00
|
|
|
outString.AssignWithConversion(" ");
|
1999-11-25 03:19:45 +03:00
|
|
|
return NS_OK;
|
|
|
|
case 2:
|
2000-04-18 11:52:02 +04:00
|
|
|
outString.Assign((PRUnichar)nbsp);
|
|
|
|
outString.AppendWithConversion(" ");
|
1999-11-25 03:19:45 +03:00
|
|
|
return NS_OK;
|
|
|
|
case 3:
|
2000-04-18 11:52:02 +04:00
|
|
|
outString.AssignWithConversion(" ");
|
1999-11-25 03:19:45 +03:00
|
|
|
outString += (PRUnichar)nbsp;
|
2000-04-18 11:52:02 +04:00
|
|
|
outString.AppendWithConversion(" ");
|
1999-11-25 03:19:45 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
if (len%2) // length is odd
|
|
|
|
{
|
|
|
|
for (j=0;j<len;j++)
|
|
|
|
{
|
2000-08-26 08:03:50 +04:00
|
|
|
if (!(j & 0x01)) outString.AppendWithConversion(" "); // even char
|
1999-11-25 03:19:45 +03:00
|
|
|
else outString += (PRUnichar)nbsp; // odd char
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-04-18 11:52:02 +04:00
|
|
|
outString.AssignWithConversion(" ");
|
1999-11-25 03:19:45 +03:00
|
|
|
outString += (PRUnichar)nbsp;
|
|
|
|
outString += (PRUnichar)nbsp;
|
|
|
|
for (j=0;j<len-3;j++)
|
|
|
|
{
|
2000-04-18 11:52:02 +04:00
|
|
|
if (!(j%2)) outString.AppendWithConversion(" "); // even char
|
1999-11-25 03:19:45 +03:00
|
|
|
else outString += (PRUnichar)nbsp; // odd char
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-09-06 23:51:59 +04:00
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::PopListItem(nsIDOMNode *aListItem, PRBool *aOutOfList)
|
|
|
|
{
|
|
|
|
// check parms
|
|
|
|
if (!aListItem || !aOutOfList)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// init out params
|
|
|
|
*aOutOfList = PR_FALSE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> curParent;
|
|
|
|
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(aListItem));
|
|
|
|
PRInt32 offset;
|
2000-12-09 07:46:08 +03:00
|
|
|
nsresult res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2000-01-26 03:57:37 +03:00
|
|
|
if (!nsHTMLEditUtils::IsListItem(curNode))
|
1999-09-06 23:51:59 +04:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// if it's first or last list item, dont need to split the list
|
|
|
|
// otherwise we do.
|
|
|
|
nsCOMPtr<nsIDOMNode> curParPar;
|
|
|
|
PRInt32 parOffset;
|
2000-12-09 07:46:08 +03:00
|
|
|
res = nsEditor::GetNodeLocation(curParent, address_of(curParPar), &parOffset);
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
PRBool bIsFirstListItem;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->IsFirstEditableChild(curNode, &bIsFirstListItem);
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
PRBool bIsLastListItem;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->IsLastEditableChild(curNode, &bIsLastListItem);
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
if (!bIsFirstListItem && !bIsLastListItem)
|
|
|
|
{
|
|
|
|
// split the list
|
|
|
|
nsCOMPtr<nsIDOMNode> newBlock;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->SplitNode(curParent, offset, getter_AddRefs(newBlock));
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bIsFirstListItem) parOffset++;
|
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->MoveNode(curNode, curParPar, parOffset);
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
// unwrap list item contents if they are no longer in a list
|
2000-01-26 03:57:37 +03:00
|
|
|
if (!nsHTMLEditUtils::IsList(curParPar)
|
|
|
|
&& nsHTMLEditUtils::IsListItem(curNode))
|
1999-09-06 23:51:59 +04:00
|
|
|
{
|
2000-04-24 15:51:12 +04:00
|
|
|
res = AddTerminatingBR(curNode);
|
2000-01-04 06:09:41 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->RemoveContainer(curNode);
|
1999-09-30 00:08:15 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-09-06 23:51:59 +04:00
|
|
|
*aOutOfList = PR_TRUE;
|
1999-11-25 03:19:45 +03:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
2000-01-10 13:13:58 +03:00
|
|
|
nsHTMLEditRules::ConfirmSelectionInBody()
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
nsresult res = NS_OK;
|
2000-01-10 13:13:58 +03:00
|
|
|
nsCOMPtr<nsIDOMElement> bodyElement;
|
|
|
|
nsCOMPtr<nsIDOMNode> bodyNode;
|
|
|
|
|
|
|
|
// get the body
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetRootElement(getter_AddRefs(bodyElement));
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!bodyElement) return NS_ERROR_UNEXPECTED;
|
|
|
|
bodyNode = do_QueryInterface(bodyElement);
|
|
|
|
|
|
|
|
// get the selection
|
2000-09-14 15:45:01 +04:00
|
|
|
nsCOMPtr<nsISelection>selection;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// get the selection start location
|
|
|
|
nsCOMPtr<nsIDOMNode> selNode, temp, parent;
|
|
|
|
PRInt32 selOffset;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetStartNodeAndOffset(selection, address_of(selNode), &selOffset);
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
temp = selNode;
|
|
|
|
|
|
|
|
// check that selNode is inside body
|
2000-01-26 03:57:37 +03:00
|
|
|
while (temp && !nsHTMLEditUtils::IsBody(temp))
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
2000-01-10 13:13:58 +03:00
|
|
|
res = temp->GetParentNode(getter_AddRefs(parent));
|
|
|
|
temp = parent;
|
1999-11-25 03:19:45 +03:00
|
|
|
}
|
2000-01-10 13:13:58 +03:00
|
|
|
|
|
|
|
// if we aren't in the body, force the issue
|
|
|
|
if (!temp)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
2000-01-10 13:13:58 +03:00
|
|
|
// uncomment this to see when we get bad selections
|
|
|
|
// NS_NOTREACHED("selection not in body");
|
|
|
|
selection->Collapse(bodyNode,0);
|
1999-11-25 03:19:45 +03:00
|
|
|
}
|
2000-01-10 13:13:58 +03:00
|
|
|
|
|
|
|
// get the selection end location
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetEndNodeAndOffset(selection, address_of(selNode), &selOffset);
|
2000-01-10 13:13:58 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
temp = selNode;
|
|
|
|
|
|
|
|
// check that selNode is inside body
|
2000-01-26 03:57:37 +03:00
|
|
|
while (temp && !nsHTMLEditUtils::IsBody(temp))
|
2000-01-10 13:13:58 +03:00
|
|
|
{
|
|
|
|
res = temp->GetParentNode(getter_AddRefs(parent));
|
|
|
|
temp = parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we aren't in the body, force the issue
|
|
|
|
if (!temp)
|
|
|
|
{
|
|
|
|
// uncomment this to see when we get bad selections
|
|
|
|
// NS_NOTREACHED("selection not in body");
|
|
|
|
selection->Collapse(bodyNode,0);
|
|
|
|
}
|
|
|
|
|
2000-01-11 04:25:00 +03:00
|
|
|
return res;
|
1999-11-25 03:19:45 +03:00
|
|
|
}
|
2000-01-10 13:13:58 +03:00
|
|
|
|
1999-11-25 03:19:45 +03:00
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::UpdateDocChangeRange(nsIDOMRange *aRange)
|
|
|
|
{
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
|
|
|
|
if (!mDocChangeRange)
|
|
|
|
{
|
2000-04-24 15:51:12 +04:00
|
|
|
// clone aRange.
|
2000-08-24 07:54:30 +04:00
|
|
|
res = aRange->CloneRange(getter_AddRefs(mDocChangeRange));
|
2000-04-24 15:51:12 +04:00
|
|
|
return res;
|
1999-11-25 03:19:45 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PRInt32 result;
|
|
|
|
|
|
|
|
// compare starts of ranges
|
2000-08-24 07:54:30 +04:00
|
|
|
res = mDocChangeRange->CompareBoundaryPoints(nsIDOMRange::START_TO_START, aRange, &result);
|
1999-09-06 23:51:59 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-12-27 03:37:01 +03:00
|
|
|
if (result > 0) // positive result means mDocChangeRange start is after aRange start
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> startNode;
|
|
|
|
PRInt32 startOffset;
|
2000-08-24 07:54:30 +04:00
|
|
|
res = aRange->GetStartContainer(getter_AddRefs(startNode));
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = aRange->GetStartOffset(&startOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = mDocChangeRange->SetStart(startNode, startOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
// compare ends of ranges
|
2000-08-24 07:54:30 +04:00
|
|
|
res = mDocChangeRange->CompareBoundaryPoints(nsIDOMRange::END_TO_END, aRange, &result);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-12-27 03:37:01 +03:00
|
|
|
if (result < 0) // negative result means mDocChangeRange end is before aRange end
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> endNode;
|
|
|
|
PRInt32 endOffset;
|
2000-08-24 07:54:30 +04:00
|
|
|
res = aRange->GetEndContainer(getter_AddRefs(endNode));
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = aRange->GetEndOffset(&endOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = mDocChangeRange->SetEnd(endNode, endOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
1999-09-06 23:51:59 +04:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2000-03-31 02:57:19 +04:00
|
|
|
nsresult
|
|
|
|
nsHTMLEditRules::InsertMozBRIfNeeded(nsIDOMNode *aNode)
|
|
|
|
{
|
|
|
|
if (!aNode) return NS_ERROR_NULL_POINTER;
|
2001-01-28 23:13:07 +03:00
|
|
|
if (!mHTMLEditor->IsBlockNode(aNode)) return NS_OK;
|
2000-03-31 02:57:19 +04:00
|
|
|
|
|
|
|
PRBool isEmpty;
|
|
|
|
nsCOMPtr<nsIDOMNode> brNode;
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res = mHTMLEditor->IsEmptyNode(aNode, &isEmpty);
|
2000-03-31 02:57:19 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (isEmpty)
|
|
|
|
{
|
2000-12-09 07:46:08 +03:00
|
|
|
res = CreateMozBR(aNode, 0, address_of(brNode));
|
2000-03-31 02:57:19 +04:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
2000-03-24 03:26:47 +03:00
|
|
|
|
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark nsIEditActionListener methods
|
|
|
|
#pragma mark -
|
|
|
|
#endif
|
1999-11-25 03:19:45 +03:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditRules::WillCreateNode(const nsString& aTag, nsIDOMNode *aParent, PRInt32 aPosition)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditRules::DidCreateNode(const nsString& aTag,
|
1999-11-25 03:19:45 +03:00
|
|
|
nsIDOMNode *aNode,
|
|
|
|
nsIDOMNode *aParent,
|
|
|
|
PRInt32 aPosition,
|
|
|
|
nsresult aResult)
|
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
if (!mListenerEnabled) return NS_OK;
|
1999-11-25 03:19:45 +03:00
|
|
|
// assumption that Join keeps the righthand node
|
2000-03-24 03:26:47 +03:00
|
|
|
nsresult res = mUtilRange->SelectNode(aNode);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
res = UpdateDocChangeRange(mUtilRange);
|
1999-11-25 03:19:45 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditRules::WillInsertNode(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aPosition)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditRules::DidInsertNode(nsIDOMNode *aNode,
|
1999-11-25 03:19:45 +03:00
|
|
|
nsIDOMNode *aParent,
|
|
|
|
PRInt32 aPosition,
|
|
|
|
nsresult aResult)
|
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
if (!mListenerEnabled) return NS_OK;
|
|
|
|
nsresult res = mUtilRange->SelectNode(aNode);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
res = UpdateDocChangeRange(mUtilRange);
|
1999-11-25 03:19:45 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditRules::WillDeleteNode(nsIDOMNode *aChild)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
if (!mListenerEnabled) return NS_OK;
|
|
|
|
nsresult res = mUtilRange->SelectNode(aChild);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
res = UpdateDocChangeRange(mUtilRange);
|
1999-11-25 03:19:45 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditRules::DidDeleteNode(nsIDOMNode *aChild, nsresult aResult)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditRules::WillSplitNode(nsIDOMNode *aExistingRightNode, PRInt32 aOffset)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditRules::DidSplitNode(nsIDOMNode *aExistingRightNode,
|
1999-11-25 03:19:45 +03:00
|
|
|
PRInt32 aOffset,
|
|
|
|
nsIDOMNode *aNewLeftNode,
|
|
|
|
nsresult aResult)
|
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
if (!mListenerEnabled) return NS_OK;
|
2000-05-03 04:14:28 +04:00
|
|
|
nsresult res = mUtilRange->SetStart(aNewLeftNode, 0);
|
2000-03-24 03:26:47 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = mUtilRange->SetEnd(aExistingRightNode, 0);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
res = UpdateDocChangeRange(mUtilRange);
|
1999-11-25 03:19:45 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditRules::WillJoinNodes(nsIDOMNode *aLeftNode, nsIDOMNode *aRightNode, nsIDOMNode *aParent)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
if (!mListenerEnabled) return NS_OK;
|
2000-02-08 15:53:34 +03:00
|
|
|
// remember split point
|
|
|
|
nsresult res = nsEditor::GetLengthOfDOMNode(aLeftNode, mJoinOffset);
|
|
|
|
return res;
|
1999-11-25 03:19:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditRules::DidJoinNodes(nsIDOMNode *aLeftNode,
|
1999-11-25 03:19:45 +03:00
|
|
|
nsIDOMNode *aRightNode,
|
|
|
|
nsIDOMNode *aParent,
|
|
|
|
nsresult aResult)
|
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
if (!mListenerEnabled) return NS_OK;
|
1999-11-25 03:19:45 +03:00
|
|
|
// assumption that Join keeps the righthand node
|
2000-03-24 03:26:47 +03:00
|
|
|
nsresult res = mUtilRange->SetStart(aRightNode, mJoinOffset);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
res = mUtilRange->SetEnd(aRightNode, mJoinOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = UpdateDocChangeRange(mUtilRange);
|
1999-11-25 03:19:45 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditRules::WillInsertText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, const nsString &aString)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditRules::DidInsertText(nsIDOMCharacterData *aTextNode,
|
1999-11-25 03:19:45 +03:00
|
|
|
PRInt32 aOffset,
|
|
|
|
const nsString &aString,
|
|
|
|
nsresult aResult)
|
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
if (!mListenerEnabled) return NS_OK;
|
1999-11-25 03:19:45 +03:00
|
|
|
PRInt32 length = aString.Length();
|
2000-03-24 03:26:47 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> theNode = do_QueryInterface(aTextNode);
|
|
|
|
nsresult res = mUtilRange->SetStart(theNode, aOffset);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
res = mUtilRange->SetEnd(theNode, aOffset+length);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = UpdateDocChangeRange(mUtilRange);
|
1999-11-25 03:19:45 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditRules::WillDeleteText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, PRInt32 aLength)
|
1999-11-25 03:19:45 +03:00
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-03-24 03:26:47 +03:00
|
|
|
nsHTMLEditRules::DidDeleteText(nsIDOMCharacterData *aTextNode,
|
1999-11-25 03:19:45 +03:00
|
|
|
PRInt32 aOffset,
|
|
|
|
PRInt32 aLength,
|
|
|
|
nsresult aResult)
|
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
if (!mListenerEnabled) return NS_OK;
|
|
|
|
nsCOMPtr<nsIDOMNode> theNode = do_QueryInterface(aTextNode);
|
|
|
|
nsresult res = mUtilRange->SetStart(theNode, aOffset);
|
1999-11-25 03:19:45 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
res = mUtilRange->SetEnd(theNode, aOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = UpdateDocChangeRange(mUtilRange);
|
1999-11-25 03:19:45 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
1999-12-07 11:30:19 +03:00
|
|
|
NS_IMETHODIMP
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection)
|
1999-12-07 11:30:19 +03:00
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
if (!mListenerEnabled) return NS_OK;
|
1999-12-07 11:30:19 +03:00
|
|
|
// get the (collapsed) selection location
|
|
|
|
nsCOMPtr<nsIDOMNode> selNode;
|
|
|
|
PRInt32 selOffset;
|
2000-03-24 03:26:47 +03:00
|
|
|
|
2001-01-28 23:13:07 +03:00
|
|
|
nsresult res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
|
1999-12-07 11:30:19 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
res = mUtilRange->SetStart(selNode, selOffset);
|
1999-12-07 11:30:19 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2001-01-28 23:13:07 +03:00
|
|
|
res = mHTMLEditor->GetEndNodeAndOffset(aSelection, address_of(selNode), &selOffset);
|
1999-12-07 11:30:19 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
res = mUtilRange->SetEnd(selNode, selOffset);
|
1999-12-07 11:30:19 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-24 03:26:47 +03:00
|
|
|
res = UpdateDocChangeRange(mUtilRange);
|
1999-12-07 11:30:19 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-09-14 15:45:01 +04:00
|
|
|
nsHTMLEditRules::DidDeleteSelection(nsISelection *aSelection)
|
1999-12-07 11:30:19 +03:00
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-11-25 03:19:45 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|