1. block transformation infrastructure is now in place. We can go ahead and implement interesting

features like set paragraph style, set list type, indent, etc.  I'm sure there's holes in my
implementation that these high level features will make obvious.

2. I've factored a lot of utility methods from several modules into nsEditor as public static methods.
This makes them easily accessable to all, and will help Joe and I remove redundant methods.

3. I changed the HTML tags to lower case, and made all string compares case-insensitive.  No, this
isn't quite the right thing to do, but we don't have atoms from layout yet.  The Right Thing is for us
to reuse those atoms.
This commit is contained in:
buster%netscape.com 1999-05-05 04:05:19 +00:00
Родитель 150cb9c442
Коммит 99a96a39ec
29 изменённых файлов: 2484 добавлений и 1610 удалений

Просмотреть файл

@ -17,12 +17,12 @@
*/ */
#include "CreateElementTxn.h" #include "CreateElementTxn.h"
#include "nsEditor.h"
#include "nsIDOMDocument.h" #include "nsIDOMDocument.h"
#include "nsIDOMNodeList.h" #include "nsIDOMNodeList.h"
#include "nsIDOMSelection.h" #include "nsIDOMSelection.h"
#include "nsIDOMText.h" #include "nsIDOMText.h"
#include "nsIDOMElement.h" #include "nsIDOMElement.h"
#include "nsIEditorSupport.h"
#ifdef NS_DEBUG #ifdef NS_DEBUG
static PRBool gNoisy = PR_FALSE; static PRBool gNoisy = PR_FALSE;
@ -125,7 +125,7 @@ NS_IMETHODIMP CreateElementTxn::Do(void)
nsresult selectionResult = mEditor->GetSelection(getter_AddRefs(selection)); nsresult selectionResult = mEditor->GetSelection(getter_AddRefs(selection));
if (NS_SUCCEEDED(selectionResult) && selection) { if (NS_SUCCEEDED(selectionResult) && selection) {
PRInt32 offset=0; PRInt32 offset=0;
nsIEditorSupport::GetChildOffset(mNewNode, mParent, offset); nsEditor::GetChildOffset(mNewNode, mParent, offset);
selectionResult = selection->Collapse(mParent, offset); selectionResult = selection->Collapse(mParent, offset);
NS_ASSERTION((NS_SUCCEEDED(selectionResult)), "selection could not be collapsed after undo of insert."); NS_ASSERTION((NS_SUCCEEDED(selectionResult)), "selection could not be collapsed after undo of insert.");
} }
@ -152,7 +152,7 @@ NS_IMETHODIMP CreateElementTxn::Undo(void)
if (NS_SUCCEEDED(selectionResult) && selection) { if (NS_SUCCEEDED(selectionResult) && selection) {
PRInt32 offset=0; PRInt32 offset=0;
if (mRefNode) { if (mRefNode) {
nsIEditorSupport::GetChildOffset(mRefNode, mParent, offset); nsEditor::GetChildOffset(mRefNode, mParent, offset);
} }
selectionResult = selection->Collapse(mParent, offset); selectionResult = selection->Collapse(mParent, offset);
NS_ASSERTION((NS_SUCCEEDED(selectionResult)), "selection could not be collapsed after undo of insert."); NS_ASSERTION((NS_SUCCEEDED(selectionResult)), "selection could not be collapsed after undo of insert.");
@ -183,7 +183,7 @@ NS_IMETHODIMP CreateElementTxn::Redo(void)
result = mEditor->GetSelection(getter_AddRefs(selection)); result = mEditor->GetSelection(getter_AddRefs(selection));
if (NS_SUCCEEDED(result) && selection) { if (NS_SUCCEEDED(result) && selection) {
PRInt32 offset=0; PRInt32 offset=0;
nsIEditorSupport::GetChildOffset(mNewNode, mParent, offset); nsEditor::GetChildOffset(mNewNode, mParent, offset);
nsresult selectionResult = selection->Collapse(mParent, offset); nsresult selectionResult = selection->Collapse(mParent, offset);
NS_ASSERTION((NS_SUCCEEDED(selectionResult)), "selection could not be collapsed after undo of insert."); NS_ASSERTION((NS_SUCCEEDED(selectionResult)), "selection could not be collapsed after undo of insert.");
} }

Просмотреть файл

@ -17,10 +17,10 @@
*/ */
#include "JoinElementTxn.h" #include "JoinElementTxn.h"
#include "nsEditor.h"
#include "nsIDOMNodeList.h" #include "nsIDOMNodeList.h"
#include "nsIDOMCharacterData.h" #include "nsIDOMCharacterData.h"
#include "nsIDOMSelection.h" #include "nsIDOMSelection.h"
#include "nsIEditorSupport.h"
#ifdef NS_DEBUG #ifdef NS_DEBUG
static PRBool gNoisy = PR_FALSE; static PRBool gNoisy = PR_FALSE;
@ -28,9 +28,6 @@ static PRBool gNoisy = PR_FALSE;
static const PRBool gNoisy = PR_FALSE; static const PRBool gNoisy = PR_FALSE;
#endif #endif
static NS_DEFINE_IID(kIEditorSupportIID, NS_IEDITORSUPPORT_IID);
JoinElementTxn::JoinElementTxn() JoinElementTxn::JoinElementTxn()
: EditTxn() : EditTxn()
{ {
@ -84,19 +81,15 @@ NS_IMETHODIMP JoinElementTxn::Do(void)
leftNodeAsText->GetLength(&mOffset); leftNodeAsText->GetLength(&mOffset);
} }
} }
nsCOMPtr<nsIEditorSupport> editor; result = nsEditor::JoinNodesImpl(mRightNode, mLeftNode, mParent, PR_FALSE);
result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); if (NS_SUCCEEDED(result))
if (NS_SUCCEEDED(result) && editor) { {
result = editor->JoinNodesImpl(mRightNode, mLeftNode, mParent, PR_FALSE); if (gNoisy) { printf(" left node = %p removed\n", mLeftNode.get()); }
if (NS_SUCCEEDED(result)) nsCOMPtr<nsIDOMSelection>selection;
mEditor->GetSelection(getter_AddRefs(selection));
if (selection)
{ {
if (gNoisy) { printf(" left node = %p removed\n", mLeftNode.get()); } selection->Collapse(mRightNode, mOffset);
nsCOMPtr<nsIDOMSelection>selection;
mEditor->GetSelection(getter_AddRefs(selection));
if (selection)
{
selection->Collapse(mRightNode, mOffset);
}
} }
} }
} }

Просмотреть файл

@ -17,10 +17,10 @@
*/ */
#include "SplitElementTxn.h" #include "SplitElementTxn.h"
#include "nsEditor.h"
#include "nsIDOMNode.h" #include "nsIDOMNode.h"
#include "nsIDOMSelection.h" #include "nsIDOMSelection.h"
#include "nsIDOMCharacterData.h" #include "nsIDOMCharacterData.h"
#include "nsIEditorSupport.h"
#ifdef NS_DEBUG #ifdef NS_DEBUG
static PRBool gNoisy = PR_FALSE; static PRBool gNoisy = PR_FALSE;
@ -28,7 +28,6 @@ static PRBool gNoisy = PR_FALSE;
static const PRBool gNoisy = PR_FALSE; static const PRBool gNoisy = PR_FALSE;
#endif #endif
static NS_DEFINE_IID(kIEditorSupportIID, NS_IEDITORSUPPORT_IID);
// note that aEditor is not refcounted // note that aEditor is not refcounted
SplitElementTxn::SplitElementTxn() SplitElementTxn::SplitElementTxn()
@ -69,19 +68,14 @@ NS_IMETHODIMP SplitElementTxn::Do(void)
// insert the new node // insert the new node
if ((NS_SUCCEEDED(result)) && (mParent)) if ((NS_SUCCEEDED(result)) && (mParent))
{ {
nsCOMPtr<nsIEditorSupport> editor; result = nsEditor::SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent);
result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); if (NS_SUCCEEDED(result) && mNewLeftNode)
if (NS_SUCCEEDED(result) && editor)
{ {
result = editor->SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent); nsCOMPtr<nsIDOMSelection>selection;
if (NS_SUCCEEDED(result) && mNewLeftNode) mEditor->GetSelection(getter_AddRefs(selection));
if (selection)
{ {
nsCOMPtr<nsIDOMSelection>selection; selection->Collapse(mNewLeftNode, mOffset);
mEditor->GetSelection(getter_AddRefs(selection));
if (selection)
{
selection->Collapse(mNewLeftNode, mOffset);
}
} }
} }
else { else {
@ -105,25 +99,20 @@ NS_IMETHODIMP SplitElementTxn::Undo(void)
// this assumes Do inserted the new node in front of the prior existing node // this assumes Do inserted the new node in front of the prior existing node
nsresult result; nsresult result;
nsCOMPtr<nsIEditorSupport> editor; result = nsEditor::JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent, PR_FALSE);
result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); if (gNoisy)
if (NS_SUCCEEDED(result) && editor) {
printf("** after join left child node %p into right node %p\n", mNewLeftNode.get(), mExistingRightNode.get());
if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
}
if (NS_SUCCEEDED(result))
{ {
result = editor->JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent, PR_FALSE); if (gNoisy) { printf(" left node = %p removed\n", mNewLeftNode.get()); }
if (gNoisy) nsCOMPtr<nsIDOMSelection>selection;
{ mEditor->GetSelection(getter_AddRefs(selection));
printf("** after join left child node %p into right node %p\n", mNewLeftNode.get(), mExistingRightNode.get()); if (selection)
if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
}
if (NS_SUCCEEDED(result))
{ {
if (gNoisy) { printf(" left node = %p removed\n", mNewLeftNode.get()); } selection->Collapse(mExistingRightNode, mOffset);
nsCOMPtr<nsIDOMSelection>selection;
mEditor->GetSelection(getter_AddRefs(selection));
if (selection)
{
selection->Collapse(mExistingRightNode, mOffset);
}
} }
} }
else { else {

Просмотреть файл

@ -43,6 +43,7 @@ nsIAtom * nsIEditProperty::tt;
nsIAtom * nsIEditProperty::u; nsIAtom * nsIEditProperty::u;
// block tags // block tags
nsIAtom * nsIEditProperty::blockquote; nsIAtom * nsIEditProperty::blockquote;
nsIAtom * nsIEditProperty::br;
nsIAtom * nsIEditProperty::h1; nsIAtom * nsIEditProperty::h1;
nsIAtom * nsIEditProperty::h2; nsIAtom * nsIEditProperty::h2;
// properties // properties
@ -56,28 +57,29 @@ void
nsEditProperty::InstanceInit() nsEditProperty::InstanceInit()
{ {
// tags // tags
nsIEditProperty::a = NS_NewAtom("A"); nsIEditProperty::a = NS_NewAtom("a");
nsIEditProperty::b = NS_NewAtom("B"); nsIEditProperty::b = NS_NewAtom("b");
nsIEditProperty::big = NS_NewAtom("BIG"); nsIEditProperty::big = NS_NewAtom("big");
nsIEditProperty::font = NS_NewAtom("FONT"); nsIEditProperty::font = NS_NewAtom("font");
nsIEditProperty::i = NS_NewAtom("I"); nsIEditProperty::i = NS_NewAtom("i");
nsIEditProperty::span = NS_NewAtom("SPAN"); nsIEditProperty::span = NS_NewAtom("span");
nsIEditProperty::small =NS_NewAtom("SMALL"); nsIEditProperty::small =NS_NewAtom("small");
nsIEditProperty::strike=NS_NewAtom("STRIKE"); nsIEditProperty::strike=NS_NewAtom("strike");
nsIEditProperty::sub = NS_NewAtom("SUB"); nsIEditProperty::sub = NS_NewAtom("sub");
nsIEditProperty::sup = NS_NewAtom("SUP"); nsIEditProperty::sup = NS_NewAtom("sup");
nsIEditProperty::tt = NS_NewAtom("TT"); nsIEditProperty::tt = NS_NewAtom("tt");
nsIEditProperty::u = NS_NewAtom("U"); nsIEditProperty::u = NS_NewAtom("u");
// tags // tags
nsIEditProperty::blockquote = NS_NewAtom("BLOCKQUOTE"); nsIEditProperty::blockquote = NS_NewAtom("blockquote");
nsIEditProperty::h1 = NS_NewAtom("H1"); nsIEditProperty::br = NS_NewAtom("br");
nsIEditProperty::h2 = NS_NewAtom("H2"); nsIEditProperty::h1 = NS_NewAtom("h1");
nsIEditProperty::h2 = NS_NewAtom("h2");
// properties // properties
nsIEditProperty::color= NS_NewAtom("COLOR"); nsIEditProperty::color= NS_NewAtom("color");
nsIEditProperty::face = NS_NewAtom("FACE"); nsIEditProperty::face = NS_NewAtom("face");
nsIEditProperty::size = NS_NewAtom("SIZE"); nsIEditProperty::size = NS_NewAtom("size");
// special // special
nsIEditProperty::allProperties = new nsString("moz_AllProperties"); nsIEditProperty::allProperties = new nsString("moz_allproperties");
} }
void void
@ -98,6 +100,7 @@ nsEditProperty::InstanceShutdown()
NS_IF_RELEASE(nsIEditProperty::u); NS_IF_RELEASE(nsIEditProperty::u);
// tags // tags
NS_IF_RELEASE(nsIEditProperty::blockquote); NS_IF_RELEASE(nsIEditProperty::blockquote);
NS_IF_RELEASE(nsIEditProperty::br);
NS_IF_RELEASE(nsIEditProperty::h1); NS_IF_RELEASE(nsIEditProperty::h1);
NS_IF_RELEASE(nsIEditProperty::h2); NS_IF_RELEASE(nsIEditProperty::h2);
// properties // properties

Просмотреть файл

@ -19,6 +19,7 @@
#include "nsIDOMDocument.h" #include "nsIDOMDocument.h"
#include "nsEditor.h" #include "nsEditor.h"
#include "nsIEditProperty.h" // to be removed XXX
#include "nsIDOMText.h" #include "nsIDOMText.h"
#include "nsIDOMElement.h" #include "nsIDOMElement.h"
#include "nsIDOMAttr.h" #include "nsIDOMAttr.h"
@ -41,6 +42,7 @@
#include "nsIEnumerator.h" #include "nsIEnumerator.h"
#include "nsIAtom.h" #include "nsIAtom.h"
#include "nsVoidArray.h" #include "nsVoidArray.h"
#include "nsISupportsArray.h"
#include "nsICaret.h" #include "nsICaret.h"
#include "nsIEditActionListener.h" #include "nsIEditActionListener.h"
@ -98,6 +100,7 @@ static NS_DEFINE_IID(kIDOMElementIID, NS_IDOMELEMENT_IID);
static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID);
static NS_DEFINE_IID(kIDOMSelectionIID, NS_IDOMSELECTION_IID); static NS_DEFINE_IID(kIDOMSelectionIID, NS_IDOMSELECTION_IID);
static NS_DEFINE_IID(kIDOMRangeIID, NS_IDOMRANGE_IID); static NS_DEFINE_IID(kIDOMRangeIID, NS_IDOMRANGE_IID);
static NS_DEFINE_CID(kCRangeCID, NS_RANGE_CID);
static NS_DEFINE_IID(kIDOMDocumentIID, NS_IDOMDOCUMENT_IID); static NS_DEFINE_IID(kIDOMDocumentIID, NS_IDOMDOCUMENT_IID);
static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID); static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID);
static NS_DEFINE_IID(kIPresShellIID, NS_IPRESSHELL_IID); static NS_DEFINE_IID(kIPresShellIID, NS_IPRESSHELL_IID);
@ -106,7 +109,6 @@ static NS_DEFINE_IID(kIEditFactoryIID, NS_IEDITORFACTORY_IID);
static NS_DEFINE_IID(kITextEditFactoryIID, NS_ITEXTEDITORFACTORY_IID); static NS_DEFINE_IID(kITextEditFactoryIID, NS_ITEXTEDITORFACTORY_IID);
static NS_DEFINE_IID(kIHTMLEditFactoryIID, NS_IHTMLEDITORFACTORY_IID); static NS_DEFINE_IID(kIHTMLEditFactoryIID, NS_IHTMLEDITORFACTORY_IID);
static NS_DEFINE_IID(kIEditorIID, NS_IEDITOR_IID); static NS_DEFINE_IID(kIEditorIID, NS_IEDITOR_IID);
static NS_DEFINE_IID(kIEditorSupportIID, NS_IEDITORSUPPORT_IID);
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kEditorCID, NS_EDITOR_CID); static NS_DEFINE_IID(kEditorCID, NS_EDITOR_CID);
static NS_DEFINE_CID(kTextEditorCID, NS_TEXTEDITOR_CID); static NS_DEFINE_CID(kTextEditorCID, NS_TEXTEDITOR_CID);
@ -144,8 +146,11 @@ static NS_DEFINE_CID(kCDOMRangeCID, NS_RANGE_CID);
#define NS_ERROR_EDITOR_NO_SELECTION NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_EDITOR,1) #define NS_ERROR_EDITOR_NO_SELECTION NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_EDITOR,1)
#define NS_ERROR_EDITOR_NO_TEXTNODE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_EDITOR,2) #define NS_ERROR_EDITOR_NO_TEXTNODE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_EDITOR,2)
const char* nsEditor::kMOZEditorBogusNodeAttr="MOZ_EDITOR_BOGUS_NODE";
const char* nsEditor::kMOZEditorBogusNodeValue="TRUE";
#ifdef NS_DEBUG_EDITOR #ifdef NS_DEBUG_EDITOR
static PRBool gNoisy = PR_FALSE; static PRBool gNoisy = PR_TRUE;
#else #else
static const PRBool gNoisy = PR_FALSE; static const PRBool gNoisy = PR_FALSE;
#endif #endif
@ -324,7 +329,7 @@ nsEditor::~nsEditor()
//BEGIN nsIEditor interface implementations // BEGIN nsEditor core implementation
NS_IMPL_ADDREF(nsEditor) NS_IMPL_ADDREF(nsEditor)
@ -351,11 +356,6 @@ nsEditor::QueryInterface(REFNSIID aIID, void** aInstancePtr)
NS_ADDREF_THIS(); NS_ADDREF_THIS();
return NS_OK; return NS_OK;
} }
if (aIID.Equals(kIEditorSupportIID)) {
*aInstancePtr = (void*)(nsIEditorSupport*)this;
NS_ADDREF_THIS();
return NS_OK;
}
return NS_NOINTERFACE; return NS_NOINTERFACE;
} }
@ -665,109 +665,6 @@ nsEditor::InsertBreak()
//BEGIN nsEditor Private methods //BEGIN nsEditor Private methods
NS_IMETHODIMP
nsEditor::GetFirstNodeOfType(nsIDOMNode *aStartNode, const nsString &aTag, nsIDOMNode **aResult)
{
nsresult result=NS_OK;
if (!mDoc)
return NS_ERROR_NULL_POINTER;
if (!aResult)
return NS_ERROR_NULL_POINTER;
/* If no node set, get root node */
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIDOMElement> element;
if (nsnull==aStartNode)
{
mDoc->GetDocumentElement(getter_AddRefs(element));
result = element->QueryInterface(kIDOMNodeIID,getter_AddRefs(node));
if (NS_FAILED(result))
return result;
if (!node)
return NS_ERROR_NULL_POINTER;
}
else
node = do_QueryInterface(aStartNode);
*aResult = nsnull;
nsCOMPtr<nsIDOMNode> childNode;
result = node->GetFirstChild(getter_AddRefs(childNode));
while (childNode)
{
result = childNode->QueryInterface(kIDOMNodeIID,getter_AddRefs(element));
nsAutoString tag;
if (NS_SUCCEEDED(result) && (element))
{
element->GetTagName(tag);
if (PR_TRUE==aTag.Equals(tag))
{
return (childNode->QueryInterface(kIDOMNodeIID,(void **) aResult)); // does the addref
}
else
{
nsresult result = GetFirstNodeOfType(childNode, aTag, aResult);
if (nsnull!=*aResult)
return result;
}
}
nsCOMPtr<nsIDOMNode> temp = childNode;
temp->GetNextSibling(getter_AddRefs(childNode));
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsEditor::GetFirstTextNode(nsIDOMNode *aNode, nsIDOMNode **aRetNode)
{
if (!aNode || !aRetNode)
{
NS_NOTREACHED("GetFirstTextNode Failed");
return NS_ERROR_NULL_POINTER;
}
PRUint16 mType;
PRBool mCNodes;
nsCOMPtr<nsIDOMNode> answer;
aNode->GetNodeType(&mType);
if (nsIDOMNode::ELEMENT_NODE == mType) {
if (NS_SUCCEEDED(aNode->HasChildNodes(&mCNodes)) && PR_TRUE == mCNodes)
{
nsCOMPtr<nsIDOMNode> node1;
nsCOMPtr<nsIDOMNode> node2;
if (!NS_SUCCEEDED(aNode->GetFirstChild(getter_AddRefs(node1))))
{
NS_NOTREACHED("GetFirstTextNode Failed");
}
while(!answer && node1)
{
GetFirstTextNode(node1, getter_AddRefs(answer));
node1->GetNextSibling(getter_AddRefs(node2));
node1 = node2;
}
}
}
else if (nsIDOMNode::TEXT_NODE == mType) {
answer = do_QueryInterface(aNode);
}
// OK, now return the answer, if any
*aRetNode = answer;
if (*aRetNode)
NS_IF_ADDREF(*aRetNode);
else
return NS_ERROR_FAILURE;
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
nsEditor::Do(nsITransaction *aTxn) nsEditor::Do(nsITransaction *aTxn)
@ -1510,7 +1407,7 @@ NS_IMETHODIMP nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNod
selectedNode = do_QueryInterface(parentSelectedNode); selectedNode = do_QueryInterface(parentSelectedNode);
selectedNode->GetParentNode(getter_AddRefs(parentSelectedNode)); selectedNode->GetParentNode(getter_AddRefs(parentSelectedNode));
selectedParentNodeAsText->GetLength(&selectedNodeContentCount); selectedParentNodeAsText->GetLength(&selectedNodeContentCount);
nsIEditorSupport::GetChildOffset(selectedNode, parentSelectedNode, indexOfTextNodeInParent); GetChildOffset(selectedNode, parentSelectedNode, indexOfTextNodeInParent);
if ((offsetOfSelectedNode!=0) && (((PRUint32)offsetOfSelectedNode)!=selectedNodeContentCount)) if ((offsetOfSelectedNode!=0) && (((PRUint32)offsetOfSelectedNode)!=selectedNodeContentCount))
{ {
@ -1518,7 +1415,7 @@ NS_IMETHODIMP nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNod
result = SplitNode(selectedNode, offsetOfSelectedNode, getter_AddRefs(newSiblingNode)); result = SplitNode(selectedNode, offsetOfSelectedNode, getter_AddRefs(newSiblingNode));
// now get the node's offset in it's parent, and insert the new tag there // now get the node's offset in it's parent, and insert the new tag there
if (NS_SUCCEEDED(result)) { if (NS_SUCCEEDED(result)) {
result = nsIEditorSupport::GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode); result = GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
} }
} }
else else
@ -1527,7 +1424,7 @@ NS_IMETHODIMP nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNod
offsetOfNewNode = indexOfTextNodeInParent; // insert new node as previous sibling to selection parent offsetOfNewNode = indexOfTextNodeInParent; // insert new node as previous sibling to selection parent
} }
else { // insert new node as last child else { // insert new node as last child
nsIEditorSupport::GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode); GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
offsetOfNewNode++; // offsets are 0-based, and we need the index of the new node offsetOfNewNode++; // offsets are 0-based, and we need the index of the new node
} }
} }
@ -1560,7 +1457,7 @@ NS_IMETHODIMP nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNod
result = SplitNode(selectedNode, offsetOfSelectedNode, getter_AddRefs(newSiblingNode)); result = SplitNode(selectedNode, offsetOfSelectedNode, getter_AddRefs(newSiblingNode));
// now get the node's offset in it's parent, and insert the new tag there // now get the node's offset in it's parent, and insert the new tag there
if (NS_SUCCEEDED(result)) { if (NS_SUCCEEDED(result)) {
result = nsIEditorSupport::GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode); result = GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
} }
} }
else else
@ -1569,7 +1466,7 @@ NS_IMETHODIMP nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNod
offsetOfNewNode = 0; // insert new node as first child offsetOfNewNode = 0; // insert new node as first child
} }
else { // insert new node as last child else { // insert new node as last child
nsIEditorSupport::GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode); GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
offsetOfNewNode++; // offsets are 0-based, and we need the index of the new node offsetOfNewNode++; // offsets are 0-based, and we need the index of the new node
} }
} }
@ -1821,108 +1718,6 @@ nsEditor::CreateTxnForDeleteInsertionPoint(nsIDOMRange *aRange,
return result; return result;
} }
NS_IMETHODIMP
nsEditor::GetPriorNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode)
{
nsresult result;
*aResultNode = nsnull;
// if aCurrentNode has a left sibling, return that sibling's rightmost child (or itself if it has no children)
result = aCurrentNode->GetPreviousSibling(aResultNode);
if ((NS_SUCCEEDED(result)) && *aResultNode)
return GetRightmostChild(*aResultNode, aResultNode);
// otherwise, walk up the parent change until there is a child that comes before
// the ancestor of aCurrentNode. Then return that node's rightmost child
nsCOMPtr<nsIDOMNode> parent(do_QueryInterface(aCurrentNode));
do {
nsCOMPtr<nsIDOMNode> node(parent);
result = node->GetParentNode(getter_AddRefs(parent));
if ((NS_SUCCEEDED(result)) && parent)
{
result = parent->GetPreviousSibling(getter_AddRefs(node));
if ((NS_SUCCEEDED(result)) && node)
{
return GetRightmostChild(node, aResultNode);
}
}
} while ((NS_SUCCEEDED(result)) && parent);
return result;
}
NS_IMETHODIMP
nsEditor::GetNextNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode)
{
nsresult result;
*aResultNode = nsnull;
// if aCurrentNode has a right sibling, return that sibling's leftmost child (or itself if it has no children)
result = aCurrentNode->GetNextSibling(aResultNode);
if ((NS_SUCCEEDED(result)) && *aResultNode)
return GetLeftmostChild(*aResultNode, aResultNode);
// otherwise, walk up the parent change until there is a child that comes before
// the ancestor of aCurrentNode. Then return that node's rightmost child
nsCOMPtr<nsIDOMNode> parent(do_QueryInterface(aCurrentNode));
do {
nsCOMPtr<nsIDOMNode> node(parent);
result = node->GetParentNode(getter_AddRefs(parent));
if ((NS_SUCCEEDED(result)) && parent)
{
result = parent->GetNextSibling(getter_AddRefs(node));
if ((NS_SUCCEEDED(result)) && node)
{
return GetLeftmostChild(node, aResultNode);
}
}
} while ((NS_SUCCEEDED(result)) && parent);
return result;
}
NS_IMETHODIMP
nsEditor::GetRightmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode)
{
nsresult result = NS_OK;
nsCOMPtr<nsIDOMNode> resultNode(do_QueryInterface(aCurrentNode));
PRBool hasChildren;
resultNode->HasChildNodes(&hasChildren);
while ((NS_SUCCEEDED(result)) && (PR_TRUE==hasChildren))
{
nsCOMPtr<nsIDOMNode> temp(resultNode);
temp->GetLastChild(getter_AddRefs(resultNode));
resultNode->HasChildNodes(&hasChildren);
}
if (NS_SUCCEEDED(result)) {
*aResultNode = resultNode;
NS_ADDREF(*aResultNode);
}
return result;
}
NS_IMETHODIMP
nsEditor::GetLeftmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode)
{
nsresult result = NS_OK;
nsCOMPtr<nsIDOMNode> resultNode(do_QueryInterface(aCurrentNode));
PRBool hasChildren;
resultNode->HasChildNodes(&hasChildren);
while ((NS_SUCCEEDED(result)) && (PR_TRUE==hasChildren))
{
nsCOMPtr<nsIDOMNode> temp(resultNode);
temp->GetFirstChild(getter_AddRefs(resultNode));
resultNode->HasChildNodes(&hasChildren);
}
if (NS_SUCCEEDED(result)) {
*aResultNode = resultNode;
NS_ADDREF(*aResultNode);
}
return result;
}
NS_IMETHODIMP NS_IMETHODIMP
nsEditor::SplitNode(nsIDOMNode * aNode, nsEditor::SplitNode(nsIDOMNode * aNode,
@ -2037,7 +1832,12 @@ NS_IMETHODIMP nsEditor::CreateTxnForJoinNode(nsIDOMNode *aLeftNode,
return result; return result;
} }
NS_IMETHODIMP
// END nsEditor core implementation
// BEGIN nsEditor public static helper methods
nsresult
nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode, nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode,
PRInt32 aOffset, PRInt32 aOffset,
nsIDOMNode* aNewLeftNode, nsIDOMNode* aNewLeftNode,
@ -2113,7 +1913,7 @@ nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode,
return result; return result;
} }
NS_IMETHODIMP nsresult
nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep, nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep,
nsIDOMNode * aNodeToJoin, nsIDOMNode * aNodeToJoin,
nsIDOMNode * aParent, nsIDOMNode * aParent,
@ -2203,7 +2003,8 @@ nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep,
return result; return result;
} }
nsresult nsIEditorSupport::GetChildOffset(nsIDOMNode *aChild, nsIDOMNode *aParent, PRInt32 &aOffset) nsresult
nsEditor::GetChildOffset(nsIDOMNode *aChild, nsIDOMNode *aParent, PRInt32 &aOffset)
{ {
NS_ASSERTION((aChild && aParent), "bad args"); NS_ASSERTION((aChild && aParent), "bad args");
nsresult result = NS_ERROR_NULL_POINTER; nsresult result = NS_ERROR_NULL_POINTER;
@ -2236,8 +2037,478 @@ nsresult nsIEditorSupport::GetChildOffset(nsIDOMNode *aChild, nsIDOMNode *aParen
return result; return result;
} }
// returns the number of things inside aNode.
// If aNode is text, returns number of characters. If not, returns number of children nodes.
nsresult
nsEditor::GetLengthOfDOMNode(nsIDOMNode *aNode, PRUint32 &aCount)
{
aCount = 0;
if (!aNode) { return NS_ERROR_NULL_POINTER; }
nsresult result=NS_OK;
nsCOMPtr<nsIDOMCharacterData>nodeAsChar;
nodeAsChar = do_QueryInterface(aNode);
if (nodeAsChar) {
nodeAsChar->GetLength(&aCount);
}
else
{
PRBool hasChildNodes;
aNode->HasChildNodes(&hasChildNodes);
if (PR_TRUE==hasChildNodes)
{
nsCOMPtr<nsIDOMNodeList>nodeList;
result = aNode->GetChildNodes(getter_AddRefs(nodeList));
if (NS_SUCCEEDED(result) && nodeList) {
nodeList->GetLength(&aCount);
}
}
}
return result;
}
// content-based inline vs. block query
nsresult
nsEditor::IsNodeInline(nsIDOMNode *aNode, PRBool &aIsInline)
{
// this is a content-based implementation
if (!aNode) { return NS_ERROR_NULL_POINTER; }
nsresult result;
aIsInline = PR_FALSE;
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(aNode);
if (element)
{
nsAutoString tag;
result = element->GetTagName(tag);
if (NS_SUCCEEDED(result))
{
nsIAtom *tagAtom = NS_NewAtom(tag);
if (!tagAtom) { return NS_ERROR_NULL_POINTER; }
if (tagAtom==nsIEditProperty::a ||
tagAtom==nsIEditProperty::b ||
tagAtom==nsIEditProperty::big ||
tagAtom==nsIEditProperty::font ||
tagAtom==nsIEditProperty::i ||
tagAtom==nsIEditProperty::span ||
tagAtom==nsIEditProperty::small ||
tagAtom==nsIEditProperty::strike ||
tagAtom==nsIEditProperty::sub ||
tagAtom==nsIEditProperty::sup ||
tagAtom==nsIEditProperty::tt ||
tagAtom==nsIEditProperty::u )
{
aIsInline = PR_TRUE;
}
}
}
return NS_OK;
}
nsresult
nsEditor::GetBlockParent(nsIDOMNode *aNode, nsIDOMElement **aBlockParent)
{
nsresult result = NS_OK;
if (!aBlockParent) {return NS_ERROR_NULL_POINTER;}
*aBlockParent = nsnull;
nsCOMPtr<nsIDOMNode>parent;
nsCOMPtr<nsIDOMNode>temp;
result = aNode->GetParentNode(getter_AddRefs(parent));
while (NS_SUCCEEDED(result) && parent)
{
PRBool isInline;
result = IsNodeInline(parent, isInline);
if (PR_FALSE==isInline)
{
parent->QueryInterface(nsIDOMElement::GetIID(), (void**)aBlockParent);
break;
}
result = parent->GetParentNode(getter_AddRefs(temp));
parent = do_QueryInterface(temp);
}
if (gNoisy) { printf("GetBlockParent for %p returning parent %p\n", aNode, *aBlockParent); }
return result;
}
nsresult
nsEditor::GetBlockSection(nsIDOMNode *aChild,
nsIDOMNode **aLeftNode,
nsIDOMNode **aRightNode)
{
nsresult result = NS_OK;
if (!aChild || !aLeftNode || !aRightNode) {return NS_ERROR_NULL_POINTER;}
*aLeftNode = aChild;
*aRightNode = aChild;
nsCOMPtr<nsIDOMNode>sibling;
result = aChild->GetPreviousSibling(getter_AddRefs(sibling));
while ((NS_SUCCEEDED(result)) && sibling)
{
PRBool isInline;
IsNodeInline(sibling, isInline);
if (PR_FALSE==isInline)
{
nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
if (!nodeAsText) {
break;
}
// XXX: needs some logic to work for other leaf nodes besides text!
}
*aLeftNode = sibling;
result = (*aLeftNode)->GetPreviousSibling(getter_AddRefs(sibling));
}
NS_ADDREF((*aLeftNode));
// now do the right side
result = aChild->GetNextSibling(getter_AddRefs(sibling));
while ((NS_SUCCEEDED(result)) && sibling)
{
PRBool isInline;
IsNodeInline(sibling, isInline);
if (PR_FALSE==isInline)
{
nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
if (!nodeAsText) {
break;
}
}
*aRightNode = sibling;
result = (*aRightNode)->GetNextSibling(getter_AddRefs(sibling));
}
NS_ADDREF((*aRightNode));
if (gNoisy) { printf("GetBlockSection returning %p %p\n",
(*aLeftNode), (*aRightNode)); }
return result;
}
nsresult
nsEditor::GetBlockSectionsForRange(nsIDOMRange *aRange, nsISupportsArray *aSections)
{
if (!aRange || !aSections) {return NS_ERROR_NULL_POINTER;}
nsresult result;
nsCOMPtr<nsIContentIterator>iter;
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
kIContentIteratorIID, getter_AddRefs(iter));
if ((NS_SUCCEEDED(result)) && iter)
{
nsCOMPtr<nsIDOMRange> lastRange;
iter->Init(aRange);
nsCOMPtr<nsIContent> currentContent;
iter->CurrentNode(getter_AddRefs(currentContent));
while (NS_COMFALSE == iter->IsDone())
{
nsCOMPtr<nsIDOMNode>currentNode = do_QueryInterface(currentContent);
if (currentNode)
{
nsCOMPtr<nsIAtom> currentContentTag;
currentContent->GetTag(*getter_AddRefs(currentContentTag));
// <BR> divides block content ranges. We can achieve this by nulling out lastRange
if (nsIEditProperty::br==currentContentTag)
{
lastRange = do_QueryInterface(nsnull);
}
else
{
PRBool isInlineOrText;
result = IsNodeInline(currentNode, isInlineOrText);
if (PR_FALSE==isInlineOrText)
{
PRUint16 nodeType;
currentNode->GetNodeType(&nodeType);
if (nsIDOMNode::TEXT_NODE == nodeType) {
isInlineOrText = PR_TRUE;
}
}
if (PR_TRUE==isInlineOrText)
{
nsCOMPtr<nsIDOMNode>leftNode;
nsCOMPtr<nsIDOMNode>rightNode;
result = GetBlockSection(currentNode,
getter_AddRefs(leftNode),
getter_AddRefs(rightNode));
if (gNoisy) {printf("currentNode %p has block content (%p,%p)\n", currentNode.get(), leftNode.get(), rightNode.get());}
if ((NS_SUCCEEDED(result)) && leftNode && rightNode)
{
// add range to the list if it doesn't overlap with the previous range
PRBool addRange=PR_TRUE;
if (lastRange)
{
nsCOMPtr<nsIDOMNode> lastStartNode;
nsCOMPtr<nsIDOMElement> blockParentOfLastStartNode;
lastRange->GetStartParent(getter_AddRefs(lastStartNode));
result = GetBlockParent(lastStartNode, getter_AddRefs(blockParentOfLastStartNode));
if ((NS_SUCCEEDED(result)) && blockParentOfLastStartNode)
{
if (gNoisy) {printf("lastStartNode %p has block parent %p\n", lastStartNode.get(), blockParentOfLastStartNode.get());}
nsCOMPtr<nsIDOMElement> blockParentOfLeftNode;
result = GetBlockParent(leftNode, getter_AddRefs(blockParentOfLeftNode));
if ((NS_SUCCEEDED(result)) && blockParentOfLeftNode)
{
if (gNoisy) {printf("leftNode %p has block parent %p\n", leftNode.get(), blockParentOfLeftNode.get());}
if (blockParentOfLastStartNode==blockParentOfLeftNode) {
addRange = PR_FALSE;
}
}
}
}
if (PR_TRUE==addRange)
{
if (gNoisy) {printf("adding range, setting lastRange with start node %p\n", leftNode.get());}
nsCOMPtr<nsIDOMRange> range;
result = nsComponentManager::CreateInstance(kCRangeCID, nsnull,
kIDOMRangeIID, getter_AddRefs(range));
if ((NS_SUCCEEDED(result)) && range)
{ // initialize the range
range->SetStart(leftNode, 0);
range->SetEnd(rightNode, 0);
aSections->AppendElement(range);
lastRange = do_QueryInterface(range);
}
}
}
}
}
}
/* do not check result here, and especially do not return the result code.
* we rely on iter->IsDone to tell us when the iteration is complete
*/
iter->Next();
iter->CurrentNode(getter_AddRefs(currentContent));
}
}
return result;
}
nsresult
nsEditor::IntermediateNodesAreInline(nsIDOMRange *aRange,
nsIDOMNode *aStartNode,
PRInt32 aStartOffset,
nsIDOMNode *aEndNode,
PRInt32 aEndOffset,
PRBool &aResult)
{
aResult = PR_TRUE; // init out param. we assume the condition is true unless we find a node that violates it
if (!aStartNode || !aEndNode || !aRange) { return NS_ERROR_NULL_POINTER; }
nsCOMPtr<nsIContentIterator>iter;
nsresult result;
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
kIContentIteratorIID, getter_AddRefs(iter));
//XXX: maybe CreateInstance is expensive, and I should keep around a static iter?
// as long as this method can't be called recursively or re-entrantly!
if ((NS_SUCCEEDED(result)) && iter)
{
nsCOMPtr<nsIContent>startContent;
startContent = do_QueryInterface(aStartNode);
nsCOMPtr<nsIContent>endContent;
endContent = do_QueryInterface(aEndNode);
if (startContent && endContent)
{
iter->Init(aRange);
nsCOMPtr<nsIContent> content;
iter->CurrentNode(getter_AddRefs(content));
while (NS_COMFALSE == iter->IsDone())
{
if ((content.get() != startContent.get()) &&
(content.get() != endContent.get()))
{
nsCOMPtr<nsIDOMNode>currentNode;
currentNode = do_QueryInterface(content);
PRBool isInline=PR_FALSE;
IsNodeInline(currentNode, isInline);
if (PR_FALSE==isInline)
{
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
nodeAsText = do_QueryInterface(currentNode);
if (!nodeAsText) // text nodes don't count in this check, so ignore them
{
aResult = PR_FALSE;
break;
}
}
}
/* do not check result here, and especially do not return the result code.
* we rely on iter->IsDone to tell us when the iteration is complete
*/
iter->Next();
iter->CurrentNode(getter_AddRefs(content));
}
}
}
return result;
}
nsresult
nsEditor::GetPriorNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode)
{
nsresult result;
*aResultNode = nsnull;
// if aCurrentNode has a left sibling, return that sibling's rightmost child (or itself if it has no children)
result = aCurrentNode->GetPreviousSibling(aResultNode);
if ((NS_SUCCEEDED(result)) && *aResultNode)
return GetRightmostChild(*aResultNode, aResultNode);
// otherwise, walk up the parent change until there is a child that comes before
// the ancestor of aCurrentNode. Then return that node's rightmost child
nsCOMPtr<nsIDOMNode> parent(do_QueryInterface(aCurrentNode));
do {
nsCOMPtr<nsIDOMNode> node(parent);
result = node->GetParentNode(getter_AddRefs(parent));
if ((NS_SUCCEEDED(result)) && parent)
{
result = parent->GetPreviousSibling(getter_AddRefs(node));
if ((NS_SUCCEEDED(result)) && node)
{
return GetRightmostChild(node, aResultNode);
}
}
} while ((NS_SUCCEEDED(result)) && parent);
return result;
}
nsresult
nsEditor::GetNextNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode)
{
nsresult result;
*aResultNode = nsnull;
// if aCurrentNode has a right sibling, return that sibling's leftmost child (or itself if it has no children)
result = aCurrentNode->GetNextSibling(aResultNode);
if ((NS_SUCCEEDED(result)) && *aResultNode)
return GetLeftmostChild(*aResultNode, aResultNode);
// otherwise, walk up the parent change until there is a child that comes before
// the ancestor of aCurrentNode. Then return that node's rightmost child
nsCOMPtr<nsIDOMNode> parent(do_QueryInterface(aCurrentNode));
do {
nsCOMPtr<nsIDOMNode> node(parent);
result = node->GetParentNode(getter_AddRefs(parent));
if ((NS_SUCCEEDED(result)) && parent)
{
result = parent->GetNextSibling(getter_AddRefs(node));
if ((NS_SUCCEEDED(result)) && node)
{
return GetLeftmostChild(node, aResultNode);
}
}
} while ((NS_SUCCEEDED(result)) && parent);
return result;
}
nsresult
nsEditor::GetRightmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode)
{
nsresult result = NS_OK;
nsCOMPtr<nsIDOMNode> resultNode(do_QueryInterface(aCurrentNode));
PRBool hasChildren;
resultNode->HasChildNodes(&hasChildren);
while ((NS_SUCCEEDED(result)) && (PR_TRUE==hasChildren))
{
nsCOMPtr<nsIDOMNode> temp(resultNode);
temp->GetLastChild(getter_AddRefs(resultNode));
resultNode->HasChildNodes(&hasChildren);
}
if (NS_SUCCEEDED(result)) {
*aResultNode = resultNode;
NS_ADDREF(*aResultNode);
}
return result;
}
nsresult
nsEditor::GetLeftmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode)
{
nsresult result = NS_OK;
nsCOMPtr<nsIDOMNode> resultNode(do_QueryInterface(aCurrentNode));
PRBool hasChildren;
resultNode->HasChildNodes(&hasChildren);
while ((NS_SUCCEEDED(result)) && (PR_TRUE==hasChildren))
{
nsCOMPtr<nsIDOMNode> temp(resultNode);
temp->GetFirstChild(getter_AddRefs(resultNode));
resultNode->HasChildNodes(&hasChildren);
}
if (NS_SUCCEEDED(result)) {
*aResultNode = resultNode;
NS_ADDREF(*aResultNode);
}
return result;
}
PRBool
nsEditor::NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag)
{
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(aNode);
if (element)
{
nsAutoString tag;
element->GetTagName(tag);
if (tag.Equals(aTag->GetUnicode()))
{
return PR_TRUE;
}
}
return PR_FALSE;
}
PRBool
nsEditor::IsEditable(nsIDOMNode *aNode)
{
if (!aNode) return PR_FALSE;
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(aNode);
if (element)
{
nsAutoString att(kMOZEditorBogusNodeAttr);
nsAutoString val;
(void)element->GetAttribute(att, val);
if (val.Equals(kMOZEditorBogusNodeValue)) {
return PR_FALSE;
}
else {
return PR_TRUE;
}
}
else
{
nsCOMPtr<nsIDOMCharacterData>text;
text = do_QueryInterface(aNode);
if (text)
{
nsAutoString data;
text->GetData(data);
PRUint32 length = data.Length();
if (0==length) {
return PR_FALSE;
}
// if the node contains only newlines, it's not editable
PRUint32 i;
for (i=0; i<length; i++)
{
if ('\n'!=data.CharAt(0)) {
return PR_TRUE;
}
}
return PR_FALSE;
}
}
return PR_TRUE;
}
//END nsEditor static utility methods
//END nsEditor Private methods
void nsEditor::HACKForceRedraw() void nsEditor::HACKForceRedraw()
{ {
@ -2398,42 +2669,96 @@ nsEditor::DebugDumpContent() const
return NS_OK; return NS_OK;
} }
//END nsEditor Private methods nsresult
nsEditor::GetFirstNodeOfType(nsIDOMNode *aStartNode,
/* ----- TEST METHODS ----- */ const nsString &aTag,
// Methods defined here are TEMPORARY nsIDOMNode **aResult)
/* ORIGINAL version by Steve - KEEP FOR REFERENCE
NS_IMETHODIMP GetColIndexForCell(nsIPresShell *aPresShell, nsIDOMNode *aCellNode, PRInt32 &aCellIndex)
{ {
aCellIndex=0; // initialize out param nsresult result=NS_OK;
nsresult result = NS_ERROR_FAILURE; // we return an error unless we get the index
if ((nsnull!=aCellNode) && (nsnull!=aPresShell)) if (!aStartNode)
{ // get the content interface return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIContent> nodeAsContent(aCellNode); if (!aResult)
if (nodeAsContent) return NS_ERROR_NULL_POINTER;
{ // get the frame from the content interface
nsISupports *layoutObject=nsnull; // frames are not ref counted, so don't use an nsCOMPtr nsCOMPtr<nsIDOMElement> element;
result = aPresShell->GetLayoutObjectFor(nodeAsContent, &layoutObject); *aResult = nsnull;
if ((NS_SUCCEEDED(result)) && (nsnull!=layoutObject)) nsCOMPtr<nsIDOMNode> childNode;
{ // get the table cell interface from the frame result = aStartNode->GetFirstChild(getter_AddRefs(childNode));
nsITableCellLayout *cellLayoutObject=nsnull; // again, frames are not ref-counted while (childNode)
result = layoutObject->QueryInterface(nsITableCellLayout::GetIID(), (void**)(&cellLayoutObject)); {
if ((NS_SUCCEEDED(result)) && (nsnull!=cellLayoutObject)) result = childNode->QueryInterface(kIDOMNodeIID,getter_AddRefs(element));
{ // get the index nsAutoString tag;
result = cellLayoutObject->GetColIndex(aCellIndex); if (NS_SUCCEEDED(result) && (element))
} {
element->GetTagName(tag);
if (PR_TRUE==aTag.Equals(tag))
{
return (childNode->QueryInterface(kIDOMNodeIID,(void **) aResult)); // does the addref
}
else
{
nsresult result = GetFirstNodeOfType(childNode, aTag, aResult);
if (nsnull!=*aResult)
return result;
}
}
nsCOMPtr<nsIDOMNode> temp = childNode;
temp->GetNextSibling(getter_AddRefs(childNode));
}
return NS_ERROR_FAILURE;
}
nsresult
nsEditor::GetFirstTextNode(nsIDOMNode *aNode, nsIDOMNode **aRetNode)
{
if (!aNode || !aRetNode)
{
NS_NOTREACHED("GetFirstTextNode Failed");
return NS_ERROR_NULL_POINTER;
}
PRUint16 mType;
PRBool mCNodes;
nsCOMPtr<nsIDOMNode> answer;
aNode->GetNodeType(&mType);
if (nsIDOMNode::ELEMENT_NODE == mType) {
if (NS_SUCCEEDED(aNode->HasChildNodes(&mCNodes)) && PR_TRUE == mCNodes)
{
nsCOMPtr<nsIDOMNode> node1;
nsCOMPtr<nsIDOMNode> node2;
if (!NS_SUCCEEDED(aNode->GetFirstChild(getter_AddRefs(node1))))
{
NS_NOTREACHED("GetFirstTextNode Failed");
}
while(!answer && node1)
{
GetFirstTextNode(node1, getter_AddRefs(answer));
node1->GetNextSibling(getter_AddRefs(node2));
node1 = node2;
} }
} }
} }
else { else if (nsIDOMNode::TEXT_NODE == mType) {
result = NS_ERROR_NULL_POINTER; answer = do_QueryInterface(aNode);
} }
return result;
}
*/
/* ----- END TEST METHODS ----- */ // OK, now return the answer, if any
*aRetNode = answer;
if (*aRetNode)
NS_IF_ADDREF(*aRetNode);
else
return NS_ERROR_FAILURE;
return NS_OK;
}
//END nsEditor Private methods
NS_IMETHODIMP nsEditor::DoInitialPreeeditInsert(const nsString& aStringToInsert) NS_IMETHODIMP nsEditor::DoInitialPreeeditInsert(const nsString& aStringToInsert)
{ {
@ -2601,3 +2926,4 @@ nsEditor::SetPreeditText(const nsString& aStringToInsert)
EndTransaction(); EndTransaction();
return result; return result;
} }

Просмотреть файл

@ -21,7 +21,6 @@
#include "prmon.h" #include "prmon.h"
#include "nsIEditor.h" #include "nsIEditor.h"
#include "nsIEditorSupport.h"
#include "nsIContextLoader.h" #include "nsIContextLoader.h"
#include "nsIDOMDocument.h" #include "nsIDOMDocument.h"
#include "nsIDOMEventListener.h" #include "nsIDOMEventListener.h"
@ -46,6 +45,7 @@ class SplitElementTxn;
class JoinElementTxn; class JoinElementTxn;
class EditAggregateTxn; class EditAggregateTxn;
class nsVoidArray; class nsVoidArray;
class nsISupportsArray;
//This is the monitor for the editor. //This is the monitor for the editor.
PRMonitor *getEditorMonitor(); PRMonitor *getEditorMonitor();
@ -56,7 +56,7 @@ PRMonitor *getEditorMonitor();
* manager, event interfaces. the idea for the event interfaces is to have them * manager, event interfaces. the idea for the event interfaces is to have them
* delegate the actual commands to the editor independent of the XPFE implementation. * delegate the actual commands to the editor independent of the XPFE implementation.
*/ */
class nsEditor : public nsIEditor, public nsIEditorSupport class nsEditor : public nsIEditor
{ {
private: private:
nsIPresShell *mPresShell; nsIPresShell *mPresShell;
@ -75,6 +75,10 @@ protected:
nsIDOMDocument * mDoc; nsIDOMDocument * mDoc;
public: public:
const static char* nsEditor::kMOZEditorBogusNodeAttr;
const static char* nsEditor::kMOZEditorBogusNodeValue;
/** The default constructor. This should suffice. the setting of the interfaces is done /** The default constructor. This should suffice. the setting of the interfaces is done
* after the construction of the editor class. * after the construction of the editor class.
*/ */
@ -186,32 +190,6 @@ public:
/*END nsIEditor interfaces*/ /*END nsIEditor interfaces*/
/*BEGIN public methods unique to nsEditor. These will get moved to an interface
if they survive.
*/
/** GetFirstTextNode ADDREFFS and will get the next available text node from the passed
* in node parameter it can also return NS_ERROR_FAILURE if no text nodes are available
* now it simply returns the first node in the dom
* @param nsIDOMNode *aNode is the node to start looking from
* @param nsIDOMNode **aRetNode is the return location of the text dom node
*
* NOTE: this method will probably be removed.
*/
NS_IMETHOD GetFirstTextNode(nsIDOMNode *aNode, nsIDOMNode **aRetNode);
/** GetFirstNodeOfType ADDREFFS and will get the next available node from the passed
* in aStartNode parameter of type aTag.
* It can also return NS_ERROR_FAILURE if no such nodes are available
* @param nsIDOMNode *aStartNode is the node to start looking from
* @param nsIAtom *aTag is the type of node we are searching for
* @param nsIDOMNode **aResult is the node we found, or nsnull if there is none
*/
NS_IMETHOD GetFirstNodeOfType(nsIDOMNode *aStartNode, const nsString &aTag, nsIDOMNode **aResult);
/*END public methods of nsEditor*/
/*BEGIN private methods used by the implementations of the above functions*/ /*BEGIN private methods used by the implementations of the above functions*/
protected: protected:
/** create a transaction for setting aAttribute to aValue on aElement /** create a transaction for setting aAttribute to aValue on aElement
@ -278,28 +256,10 @@ protected:
PRUint32 aOffset, PRUint32 aOffset,
SplitElementTxn **aTxn); SplitElementTxn **aTxn);
NS_IMETHOD SplitNodeImpl(nsIDOMNode * aExistingRightNode,
PRInt32 aOffset,
nsIDOMNode * aNewLeftNode,
nsIDOMNode * aParent);
NS_IMETHOD CreateTxnForJoinNode(nsIDOMNode *aLeftNode, NS_IMETHOD CreateTxnForJoinNode(nsIDOMNode *aLeftNode,
nsIDOMNode *aRightNode, nsIDOMNode *aRightNode,
JoinElementTxn **aTxn); JoinElementTxn **aTxn);
NS_IMETHOD JoinNodesImpl(nsIDOMNode * aNodeToKeep,
nsIDOMNode * aNodeToJoin,
nsIDOMNode * aParent,
PRBool aNodeToKeepIsFirst);
NS_IMETHOD GetPriorNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode);
NS_IMETHOD GetNextNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode);
NS_IMETHOD GetRightmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode);
NS_IMETHOD GetLeftmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode);
/** Create an aggregate transaction for deleting current selection /** Create an aggregate transaction for deleting current selection
* Used by all methods that need to delete current selection, * Used by all methods that need to delete current selection,
* then insert something new to replace it * then insert something new to replace it
@ -321,11 +281,152 @@ protected:
// of an error in Gecko which is not rendering the // of an error in Gecko which is not rendering the
// document after a change via the DOM - gpk 2/13/99 // document after a change via the DOM - gpk 2/13/99
void HACKForceRedraw(void); void HACKForceRedraw(void);
PRBool mIMEFirstTransaction; PRBool mIMEFirstTransaction;
NS_IMETHOD DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNode> &parentSelectedNode, PRInt32& offsetOfNewNode); NS_IMETHOD DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNode> &parentSelectedNode, PRInt32& offsetOfNewNode);
public:
/**
* SplitNode() creates a new node identical to an existing node, and split the contents between the two nodes
* @param aExistingRightNode the node to split. It will become the new node's next sibling.
* @param aOffset the offset of aExistingRightNode's content|children to do the split at
* @param aNewLeftNode [OUT] the new node resulting from the split, becomes aExistingRightNode's previous sibling.
* @param aParent the parent of aExistingRightNode
*/
static nsresult SplitNodeImpl(nsIDOMNode *aExistingRightNode,
PRInt32 aOffset,
nsIDOMNode *aNewLeftNode,
nsIDOMNode *aParent);
/**
* JoinNodes() takes 2 nodes and merge their content|children.
* @param aNodeToKeep The node that will remain after the join.
* @param aNodeToJoin The node that will be joined with aNodeToKeep.
* There is no requirement that the two nodes be of the same type.
* @param aParent The parent of aExistingRightNode
* @param aNodeToKeepIsFirst if PR_TRUE, the contents|children of aNodeToKeep come before the
* contents|children of aNodeToJoin, otherwise their positions are switched.
*/
static nsresult JoinNodesImpl(nsIDOMNode *aNodeToKeep,
nsIDOMNode *aNodeToJoin,
nsIDOMNode *aParent,
PRBool aNodeToKeepIsFirst);
/**
* Set aOffset to the offset of aChild in aParent.
* Returns an error if aChild is not an immediate child of aParent.
*/
static nsresult GetChildOffset(nsIDOMNode *aChild,
nsIDOMNode *aParent,
PRInt32 &aOffset);
/** set aIsInline to PR_TRUE if aNode is inline as defined by HTML DTD */
static nsresult IsNodeInline(nsIDOMNode *aNode, PRBool &aIsInline);
/** returns the closest block parent of aNode, not including aNode itself.
* can return null, for example if aNode is in a document fragment.
* @param aNode The node whose parent we seek.
* @param aBlockParent [OUT] The block parent, if any.
* @return a success value unless an unexpected error occurs.
*/
static nsresult GetBlockParent(nsIDOMNode *aNode,
nsIDOMElement **aBlockParent);
/** Determines the bounding nodes for the block section containing aNode.
* The calculation is based on some nodes intrinsically being block elements
* acording to HTML. Style sheets are not considered in this calculation.
* <BR> tags separate block content sections. So the HTML markup:
* <PRE>
* <P>text1<BR>text2<B>text3</B></P>
* </PRE>
* contains two block content sections. The first has the text node "text1"
* for both endpoints. The second has "text2" as the left endpoint and
* "text3" as the right endpoint.
* Notice that offsets aren't required, only leaf nodes. Offsets are implicit.
*
* @param aNode the block content returned includes aNode
* @param aLeftNode [OUT] the left endpoint of the block content containing aNode
* @param aRightNode [OUT] the right endpoint of the block content containing aNode
*
*/
static nsresult GetBlockSection(nsIDOMNode *aNode,
nsIDOMNode **aLeftNode,
nsIDOMNode **aRightNode);
/** Compute the set of block sections in a given range.
* A block section is the set of (leftNode, rightNode) pairs given
* by GetBlockSection. The set is computed by computing the
* block section for every leaf node in the range and throwing
* out duplicates.
*
* @param aRange The range to compute block sections for.
* @param aSections Allocated storage for the resulting set, stored as nsIDOMRanges.
*/
static nsresult GetBlockSectionsForRange(nsIDOMRange *aRange,
nsISupportsArray *aSections);
/** returns PR_TRUE in out-param aResult if all nodes between (aStartNode, aStartOffset)
* and (aEndNode, aEndOffset) are inline as defined by HTML DTD.
*/
static nsresult IntermediateNodesAreInline(nsIDOMRange *aRange,
nsIDOMNode *aStartNode,
PRInt32 aStartOffset,
nsIDOMNode *aEndNode,
PRInt32 aEndOffset,
PRBool &aResult);
/** returns the number of things inside aNode in the out-param aCount.
* @param aNode is the node to get the length of.
* If aNode is text, returns number of characters.
* If not, returns number of children nodes.
* @param aCount [OUT] the result of the above calculation.
*/
static nsresult GetLengthOfDOMNode(nsIDOMNode *aNode, PRUint32 &aCount);
/**
*/
static nsresult GetPriorNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode);
/**
*/
static nsresult GetNextNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode);
/**
*/
static nsresult GetRightmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode);
/**
*/
static nsresult GetLeftmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode);
/** GetFirstTextNode ADDREFFS and will get the next available text node from the passed
* in node parameter it can also return NS_ERROR_FAILURE if no text nodes are available
* now it simply returns the first node in the dom
* @param nsIDOMNode *aNode is the node to start looking from
* @param nsIDOMNode **aRetNode is the return location of the text dom node
*
* NOTE: this method will probably be removed.
*/
static nsresult GetFirstTextNode(nsIDOMNode *aNode, nsIDOMNode **aRetNode);
/** GetFirstNodeOfType ADDREFFS and will get the next available node from the passed
* in aStartNode parameter of type aTag.
* It can also return NS_ERROR_FAILURE if no such nodes are available
* @param aStartNode is the node to start looking from
* @param aTag is the type of node we are searching for
* @param aResult is the node we found, or nsnull if there is none
*/
static nsresult GetFirstNodeOfType(nsIDOMNode *aStartNode,
const nsString &aTag,
nsIDOMNode **aResult);
/** returns PR_TRUE if aNode is of the type implied by aTag */
static PRBool NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag);
/** returns PR_TRUE if aNode is an editable node */
static PRBool IsEditable(nsIDOMNode *aNode);
}; };

Просмотреть файл

@ -25,6 +25,7 @@
#include "nsIDOMCharacterData.h" #include "nsIDOMCharacterData.h"
#include "nsIEditProperty.h" #include "nsIEditProperty.h"
#include "nsISupportsArray.h" #include "nsISupportsArray.h"
#include "nsVoidArray.h"
#include "nsString.h" #include "nsString.h"
#include "nsIStringStream.h" #include "nsIStringStream.h"
@ -599,7 +600,39 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr
nsCOMPtr<nsIHTMLEditor>htmlEditor; nsCOMPtr<nsIHTMLEditor>htmlEditor;
htmlEditor = do_QueryInterface(mEditor); htmlEditor = do_QueryInterface(mEditor);
if (htmlEditor) { if (htmlEditor) {
htmlEditor->RemoveBlockParent(); htmlEditor->RemoveParagraphStyle();
}
}
}
break;
// hard-coded change structure test -- GetParagraphStyle
case nsIDOMEvent::VK_0:
if (PR_TRUE==ctrlKey)
{
aProcessed=PR_TRUE;
if (mEditor)
{
nsCOMPtr<nsIHTMLEditor>htmlEditor;
htmlEditor = do_QueryInterface(mEditor);
if (htmlEditor)
{
printf("testing GetParagraphStyle\n");
nsStringArray styles;
nsresult result = htmlEditor->GetParagraphStyle(&styles);
if (NS_SUCCEEDED(result))
{
PRInt32 count = styles.Count();
PRInt32 i;
for (i=0; i<count; i++)
{
nsString *tag = styles.StringAt(i);
char *tagCString = tag->ToNewCString();
printf("%s ", tagCString);
delete [] tagCString;
}
printf("\n");
}
} }
} }
} }

Просмотреть файл

@ -40,7 +40,6 @@
#include "nsIComponentManager.h" #include "nsIComponentManager.h"
#include "nsIServiceManager.h" #include "nsIServiceManager.h"
#include "nsITableCellLayout.h" //For GetColIndexForCell
static NS_DEFINE_IID(kIDOMEventReceiverIID, NS_IDOMEVENTRECEIVER_IID); static NS_DEFINE_IID(kIDOMEventReceiverIID, NS_IDOMEVENTRECEIVER_IID);
@ -59,7 +58,7 @@ static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID);
static NS_DEFINE_IID(kIContentIteratorIID, NS_ICONTENTITERTOR_IID); static NS_DEFINE_IID(kIContentIteratorIID, NS_ICONTENTITERTOR_IID);
#ifdef NS_DEBUG #ifdef NS_DEBUG
static PRBool gNoisy = PR_FALSE; static PRBool gNoisy = PR_TRUE;
#else #else
static const PRBool gNoisy = PR_FALSE; static const PRBool gNoisy = PR_FALSE;
#endif #endif
@ -205,7 +204,7 @@ NS_IMETHODIMP nsHTMLEditor::InsertBreak()
if (-1==offsetInParent) if (-1==offsetInParent)
{ {
nextNode->GetParentNode(getter_AddRefs(parent)); nextNode->GetParentNode(getter_AddRefs(parent));
result = nsIEditorSupport::GetChildOffset(nextNode, parent, offsetInParent); result = GetChildOffset(nextNode, parent, offsetInParent);
if (NS_SUCCEEDED(result)) { if (NS_SUCCEEDED(result)) {
selection->Collapse(parent, offsetInParent+1); // +1 to insert just after the break selection->Collapse(parent, offsetInParent+1); // +1 to insert just after the break
} }
@ -395,17 +394,17 @@ nsHTMLEditor::GetParagraphStyle(nsStringArray *aTagList)
if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem))
{ {
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) ); nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
// scan the range for all the independent block content subranges // scan the range for all the independent block content blockSections
// and get the block parent of each // and get the block parent of each
nsISupportsArray *subRanges; nsISupportsArray *blockSections;
result = NS_NewISupportsArray(&subRanges); result = NS_NewISupportsArray(&blockSections);
if ((NS_SUCCEEDED(result)) && subRanges) if ((NS_SUCCEEDED(result)) && blockSections)
{ {
result = GetBlockRanges(range, subRanges); result = GetBlockSectionsForRange(range, blockSections);
if (NS_SUCCEEDED(result)) if (NS_SUCCEEDED(result))
{ {
nsIDOMRange *subRange; nsIDOMRange *subRange;
subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
while (subRange && (NS_SUCCEEDED(result))) while (subRange && (NS_SUCCEEDED(result)))
{ {
nsCOMPtr<nsIDOMNode>startParent; nsCOMPtr<nsIDOMNode>startParent;
@ -418,17 +417,19 @@ nsHTMLEditor::GetParagraphStyle(nsStringArray *aTagList)
{ {
nsAutoString blockParentTag; nsAutoString blockParentTag;
blockParent->GetTagName(blockParentTag); blockParent->GetTagName(blockParentTag);
if (-1==aTagList->IndexOf(blockParentTag)) { PRBool isRoot;
IsRootTag(blockParentTag, isRoot);
if ((PR_FALSE==isRoot) && (-1==aTagList->IndexOf(blockParentTag))) {
aTagList->AppendString(blockParentTag); aTagList->AppendString(blockParentTag);
} }
} }
} }
NS_RELEASE(subRange); NS_RELEASE(subRange);
subRanges->RemoveElementAt(0); blockSections->RemoveElementAt(0);
subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
} }
} }
NS_RELEASE(subRanges); NS_RELEASE(blockSections);
} }
} }
} }
@ -465,7 +466,7 @@ nsHTMLEditor::AddBlockParent(nsString& aParentTag)
if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem))
{ {
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) ); nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
// scan the range for all the independent block content subranges // scan the range for all the independent block content blockSections
// and apply the transformation to them // and apply the transformation to them
result = ReParentContentOfRange(range, aParentTag, eInsertParent); result = ReParentContentOfRange(range, aParentTag, eInsertParent);
} }
@ -510,47 +511,30 @@ nsHTMLEditor::ReplaceBlockParent(nsString& aParentTag)
if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem))
{ {
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) ); nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
// scan the range for all the independent block content subranges // scan the range for all the independent block content blockSections
// and apply the transformation to them // and apply the transformation to them
result = ReParentContentOfRange(range, aParentTag, eReplaceParent); result = ReParentContentOfRange(range, aParentTag, eReplaceParent);
} }
} }
nsEditor::EndTransaction(); nsEditor::EndTransaction();
if (NS_SUCCEEDED(result))
{ // set the selection
// XXX: can't do anything until I can create ranges
}
} }
if (gNoisy) {printf("Finished nsHTMLEditor::AddBlockParent with this content:\n"); DebugDumpContent(); } // DEBUG if (gNoisy) {printf("Finished nsHTMLEditor::AddBlockParent with this content:\n"); DebugDumpContent(); } // DEBUG
return result; return result;
} }
void IsRootTag(nsString &aTag, PRBool &aIsTag)
{
static nsAutoString bodyTag = "body";
static nsAutoString tdTag = "td";
static nsAutoString thTag = "th";
static nsAutoString captionTag = "caption";
if (PR_TRUE==aTag.EqualsIgnoreCase(bodyTag) ||
PR_TRUE==aTag.EqualsIgnoreCase(tdTag) ||
PR_TRUE==aTag.EqualsIgnoreCase(thTag) ||
PR_TRUE==aTag.EqualsIgnoreCase(captionTag) )
{
aIsTag = PR_TRUE;
}
else {
aIsTag = PR_FALSE;
}
}
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode, nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode,
nsString &aParentTag, nsString &aParentTag,
BlockTransformationType aTransformation) BlockTransformationType aTransformation)
{ {
if (!aNode) { return NS_ERROR_NULL_POINTER; } if (!aNode) { return NS_ERROR_NULL_POINTER; }
if (gNoisy)
{
char *tag = aParentTag.ToNewCString();
printf("---------- ReParentContentOfNode(%p,%s,%d) -----------\n", aNode, tag, aTransformation);
delete [] tag;
}
// find the current block parent, or just use aNode if it is a block node // find the current block parent, or just use aNode if it is a block node
nsCOMPtr<nsIDOMElement>blockParentElement; nsCOMPtr<nsIDOMElement>blockParentElement;
nsCOMPtr<nsIDOMNode>nodeToReParent; // this is the node we'll operate on, by default it's aNode nsCOMPtr<nsIDOMNode>nodeToReParent; // this is the node we'll operate on, by default it's aNode
@ -606,7 +590,7 @@ nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode,
{ // this is the case of an insertion point between 2 non-text objects { // this is the case of an insertion point between 2 non-text objects
// XXX: how to you know it's an insertion point??? // XXX: how to you know it's an insertion point???
PRInt32 offsetInParent=0; PRInt32 offsetInParent=0;
result = nsIEditorSupport::GetChildOffset(nodeToReParent, blockParentNode, offsetInParent); result = GetChildOffset(nodeToReParent, blockParentNode, offsetInParent);
NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset"); NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset");
// otherwise, just create the block parent at the selection // otherwise, just create the block parent at the selection
result = nsTextEditor::CreateNode(aParentTag, blockParentNode, offsetInParent, result = nsTextEditor::CreateNode(aParentTag, blockParentNode, offsetInParent,
@ -654,10 +638,14 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode,
nsString &aParentTag, nsString &aParentTag,
nsIDOMNode *aBlockParentNode, nsIDOMNode *aBlockParentNode,
nsString &aBlockParentTag, nsString &aBlockParentTag,
BlockTransformationType aTranformation, BlockTransformationType aTransformation,
nsIDOMNode **aNewParentNode) nsIDOMNode **aNewParentNode)
{ {
if (!aNode || !aBlockParentNode || !aNewParentNode) { return NS_ERROR_NULL_POINTER; } if (!aNode || !aBlockParentNode || !aNewParentNode) { return NS_ERROR_NULL_POINTER; }
nsCOMPtr<nsIDOMNode> blockParentNode = do_QueryInterface(aBlockParentNode);
PRBool removeBlockParent = PR_FALSE;
PRBool removeBreakBefore = PR_FALSE;
PRBool removeBreakAfter = PR_FALSE;
nsCOMPtr<nsIDOMNode>ancestor; nsCOMPtr<nsIDOMNode>ancestor;
nsresult result = aNode->GetParentNode(getter_AddRefs(ancestor)); nsresult result = aNode->GetParentNode(getter_AddRefs(ancestor));
nsCOMPtr<nsIDOMNode>previousAncestor = do_QueryInterface(aNode); nsCOMPtr<nsIDOMNode>previousAncestor = do_QueryInterface(aNode);
@ -675,46 +663,87 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode,
} }
// now, previousAncestor is the node we are operating on // now, previousAncestor is the node we are operating on
nsCOMPtr<nsIDOMNode>leftNode, rightNode; nsCOMPtr<nsIDOMNode>leftNode, rightNode;
result = GetBlockDelimitedContent(previousAncestor, result = GetBlockSection(previousAncestor,
getter_AddRefs(leftNode), getter_AddRefs(leftNode),
getter_AddRefs(rightNode)); getter_AddRefs(rightNode));
if ((NS_SUCCEEDED(result)) && leftNode && rightNode) if ((NS_SUCCEEDED(result)) && leftNode && rightNode)
{ {
PRInt32 offsetInParent=0; // determine some state for managing <BR>s around the new block
if (eInsertParent==aTranformation) PRBool isSubordinateBlock = PR_FALSE; // if true, the content is already in a subordinate block
PRBool isRootBlock = PR_FALSE; // if true, the content is in a root block
nsCOMPtr<nsIDOMElement>blockParentElement = do_QueryInterface(blockParentNode);
if (blockParentElement)
{ {
result = nsIEditorSupport::GetChildOffset(leftNode, aBlockParentNode, offsetInParent); nsAutoString blockParentTag;
blockParentElement->GetTagName(blockParentTag);
IsSubordinateBlock(blockParentTag, isSubordinateBlock);
IsRootTag(blockParentTag, isRootBlock);
}
if (PR_TRUE==isRootBlock)
{ // we're creating a block element where a block element did not previously exist
removeBreakBefore = PR_TRUE;
removeBreakAfter = PR_TRUE;
}
// apply the transformation
PRInt32 offsetInParent=0;
if (eInsertParent==aTransformation || PR_TRUE==isRootBlock)
{
result = GetChildOffset(leftNode, blockParentNode, offsetInParent);
NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset"); NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset");
result = nsTextEditor::CreateNode(aParentTag, aBlockParentNode, offsetInParent, aNewParentNode); result = nsTextEditor::CreateNode(aParentTag, blockParentNode, offsetInParent, aNewParentNode);
if (gNoisy) { printf("created a node in aBlockParentNode at offset %d\n", offsetInParent); } if (gNoisy) { printf("created a node in blockParentNode at offset %d\n", offsetInParent); }
} }
else else
{ {
nsCOMPtr<nsIDOMNode> grandParent; nsCOMPtr<nsIDOMNode> grandParent;
result = aBlockParentNode->GetParentNode(getter_AddRefs(grandParent)); result = blockParentNode->GetParentNode(getter_AddRefs(grandParent));
if ((NS_SUCCEEDED(result)) && grandParent) if ((NS_SUCCEEDED(result)) && grandParent)
{ {
nsCOMPtr<nsIDOMNode>firstChildNode, lastChildNode; nsCOMPtr<nsIDOMNode>firstChildNode, lastChildNode;
aBlockParentNode->GetFirstChild(getter_AddRefs(firstChildNode)); blockParentNode->GetFirstChild(getter_AddRefs(firstChildNode));
aBlockParentNode->GetLastChild(getter_AddRefs(lastChildNode)); blockParentNode->GetLastChild(getter_AddRefs(lastChildNode));
if (firstChildNode==leftNode && lastChildNode==rightNode) if (firstChildNode==leftNode && lastChildNode==rightNode)
{ {
result = nsIEditorSupport::GetChildOffset(aBlockParentNode, grandParent, offsetInParent); result = GetChildOffset(blockParentNode, grandParent, offsetInParent);
NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset"); NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset");
result = nsTextEditor::CreateNode(aParentTag, grandParent, offsetInParent, aNewParentNode); result = nsTextEditor::CreateNode(aParentTag, grandParent, offsetInParent, aNewParentNode);
if (gNoisy) { printf("created a node in grandParent at offset %d\n", offsetInParent); } if (gNoisy) { printf("created a node in grandParent at offset %d\n", offsetInParent); }
} }
else else
{ {
result = nsIEditorSupport::GetChildOffset(leftNode, aBlockParentNode, offsetInParent); // We're in the case where the content of blockParentNode is separated by <BR>'s,
// creating multiple block content ranges.
// Split blockParentNode around the blockContent
if (gNoisy) { printf("splitting a node because of <BR>s\n"); }
nsCOMPtr<nsIDOMNode> newLeftNode;
if (firstChildNode!=leftNode)
{
result = GetChildOffset(leftNode, blockParentNode, offsetInParent);
if (gNoisy) { printf("splitting left at %d\n", offsetInParent); }
result = SplitNode(blockParentNode, offsetInParent, getter_AddRefs(newLeftNode));
// after this split, blockParentNode still contains leftNode and rightNode
}
if (lastChildNode!=rightNode)
{
result = GetChildOffset(rightNode, blockParentNode, offsetInParent);
offsetInParent++;
if (gNoisy) { printf("splitting right at %d\n", offsetInParent); }
result = SplitNode(blockParentNode, offsetInParent, getter_AddRefs(newLeftNode));
blockParentNode = do_QueryInterface(newLeftNode);
}
result = GetChildOffset(leftNode, blockParentNode, offsetInParent);
NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset"); NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset");
result = nsTextEditor::CreateNode(aParentTag, aBlockParentNode, offsetInParent, aNewParentNode); result = nsTextEditor::CreateNode(aParentTag, blockParentNode, offsetInParent, aNewParentNode);
if (gNoisy) { printf("created a node in aBlockParentNode at offset %d\n", offsetInParent); } if (gNoisy) { printf("created a node in blockParentNode at offset %d\n", offsetInParent); }
// what we need to do here is remove the existing block parent when we're all done.
removeBlockParent = PR_TRUE;
} }
} }
} }
if ((NS_SUCCEEDED(result)) && *aNewParentNode) if ((NS_SUCCEEDED(result)) && *aNewParentNode)
{ // move all the children/contents of aBlockParentNode to aNewParentNode { // move all the children/contents of blockParentNode to aNewParentNode
nsCOMPtr<nsIDOMNode>childNode = do_QueryInterface(rightNode); nsCOMPtr<nsIDOMNode>childNode = do_QueryInterface(rightNode);
nsCOMPtr<nsIDOMNode>previousSiblingNode; nsCOMPtr<nsIDOMNode>previousSiblingNode;
while (NS_SUCCEEDED(result) && childNode) while (NS_SUCCEEDED(result) && childNode)
@ -737,6 +766,73 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode,
childNode = do_QueryInterface(previousSiblingNode); childNode = do_QueryInterface(previousSiblingNode);
} // end while loop } // end while loop
} }
// clean up the surrounding content to maintain vertical whitespace
if (NS_SUCCEEDED(result))
{
// if the prior node is a <BR> and we did something to change vertical whitespacing, delete the <BR>
nsCOMPtr<nsIDOMNode> brNode;
result = GetPriorNode(leftNode, getter_AddRefs(brNode));
if (NS_SUCCEEDED(result) && brNode)
{
nsCOMPtr<nsIContent> brContent = do_QueryInterface(brNode);
if (brContent)
{
nsCOMPtr<nsIAtom> brContentTag;
brContent->GetTag(*getter_AddRefs(brContentTag));
if (nsIEditProperty::br==brContentTag) {
result = DeleteNode(brNode);
}
}
}
// if the next node is a <BR> and we did something to change vertical whitespacing, delete the <BR>
if (NS_SUCCEEDED(result))
{
result = GetNextNode(rightNode, getter_AddRefs(brNode));
if (NS_SUCCEEDED(result) && brNode)
{
nsCOMPtr<nsIContent> brContent = do_QueryInterface(brNode);
if (brContent)
{
nsCOMPtr<nsIAtom> brContentTag;
brContent->GetTag(*getter_AddRefs(brContentTag));
if (nsIEditProperty::br==brContentTag) {
result = DeleteNode(brNode);
}
}
}
}
}
if ((NS_SUCCEEDED(result)) && (PR_TRUE==removeBlockParent))
{ // we determined we need to remove the previous block parent. Do it!
// go through list backwards so deletes don't interfere with the iteration
nsCOMPtr<nsIDOMNodeList> childNodes;
result = blockParentNode->GetChildNodes(getter_AddRefs(childNodes));
if ((NS_SUCCEEDED(result)) && (childNodes))
{
nsCOMPtr<nsIDOMNode>grandParent;
blockParentNode->GetParentNode(getter_AddRefs(grandParent));
PRInt32 offsetInParent;
result = GetChildOffset(blockParentNode, grandParent, offsetInParent);
PRUint32 childCount;
childNodes->GetLength(&childCount);
PRInt32 i=childCount-1;
for ( ; ((NS_SUCCEEDED(result)) && (0<=i)); i--)
{
nsCOMPtr<nsIDOMNode> childNode;
result = childNodes->Item(i, getter_AddRefs(childNode));
if ((NS_SUCCEEDED(result)) && (childNode))
{
result = nsTextEditor::DeleteNode(childNode);
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::InsertNode(childNode, grandParent, offsetInParent);
}
}
}
if (gNoisy) { printf("removing the old block parent %p\n", blockParentNode.get()); }
result = nsTextEditor::DeleteNode(blockParentNode);
}
}
} }
return result; return result;
} }
@ -748,29 +844,30 @@ nsHTMLEditor::ReParentContentOfRange(nsIDOMRange *aRange,
{ {
if (!aRange) { return NS_ERROR_NULL_POINTER; } if (!aRange) { return NS_ERROR_NULL_POINTER; }
nsresult result; nsresult result;
nsISupportsArray *subRanges; nsISupportsArray *blockSections;
result = NS_NewISupportsArray(&subRanges); result = NS_NewISupportsArray(&blockSections);
if ((NS_SUCCEEDED(result)) && subRanges) if ((NS_SUCCEEDED(result)) && blockSections)
{ {
result = GetBlockRanges(aRange, subRanges); result = GetBlockSectionsForRange(aRange, blockSections);
if (NS_SUCCEEDED(result)) if (NS_SUCCEEDED(result))
{ {
nsIDOMRange *subRange; nsIDOMRange *subRange;
subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
while (subRange && (NS_SUCCEEDED(result))) while (subRange && (NS_SUCCEEDED(result)))
{ {
nsCOMPtr<nsIDOMNode>startParent; nsCOMPtr<nsIDOMNode>startParent;
result = subRange->GetStartParent(getter_AddRefs(startParent)); result = subRange->GetStartParent(getter_AddRefs(startParent));
if (NS_SUCCEEDED(result) && startParent) if (NS_SUCCEEDED(result) && startParent)
{ {
if (gNoisy) { printf("ReParentContentOfRange calling ReParentContentOfNode\n"); }
result = ReParentContentOfNode(startParent, aParentTag, aTranformation); result = ReParentContentOfNode(startParent, aParentTag, aTranformation);
} }
NS_RELEASE(subRange); NS_RELEASE(subRange);
subRanges->RemoveElementAt(0); blockSections->RemoveElementAt(0);
subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
} }
} }
NS_RELEASE(subRanges); NS_RELEASE(blockSections);
} }
return result; return result;
} }
@ -793,10 +890,10 @@ nsHTMLEditor::CanContainBlock(nsString &aBlockChild, nsString &aBlockParent, PRB
} }
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLEditor::RemoveBlockParent() nsHTMLEditor::RemoveParagraphStyle()
{ {
if (gNoisy) { if (gNoisy) {
printf("---------- nsHTMLEditor::RemoveBlockParent ----------\n"); printf("---------- nsHTMLEditor::RemoveParagraphStyle ----------\n");
} }
nsresult result=NS_ERROR_NOT_INITIALIZED; nsresult result=NS_ERROR_NOT_INITIALIZED;
@ -815,65 +912,7 @@ nsHTMLEditor::RemoveBlockParent()
if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem))
{ {
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) ); nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
nsCOMPtr<nsIDOMNode>commonParent; result = RemoveParagraphStyleFromRange(range);
result = range->GetCommonParent(getter_AddRefs(commonParent));
if ((NS_SUCCEEDED(result)) && commonParent)
{
PRInt32 startOffset, endOffset;
range->GetStartOffset(&startOffset);
range->GetEndOffset(&endOffset);
nsCOMPtr<nsIDOMNode> startParent; nsCOMPtr<nsIDOMNode> endParent;
range->GetStartParent(getter_AddRefs(startParent));
range->GetEndParent(getter_AddRefs(endParent));
if (startParent.get()==endParent.get())
{ // the range is entirely contained within a single node
nsCOMPtr<nsIDOMElement>blockParentElement;
result = nsTextEditor::GetBlockParent(startParent, getter_AddRefs(blockParentElement));
while ((NS_SUCCEEDED(result)) && blockParentElement)
{
nsAutoString childTag; // leave as empty string
nsAutoString blockParentTag;
blockParentElement->GetTagName(blockParentTag);
PRBool canContain;
CanContainBlock(childTag, blockParentTag, canContain);
if (PR_TRUE==canContain) {
break;
}
else
{
// go through list backwards so deletes don't interfere with the iteration
nsCOMPtr<nsIDOMNodeList> childNodes;
result = blockParentElement->GetChildNodes(getter_AddRefs(childNodes));
if ((NS_SUCCEEDED(result)) && (childNodes))
{
nsCOMPtr<nsIDOMNode>grandParent;
blockParentElement->GetParentNode(getter_AddRefs(grandParent));
PRInt32 offsetInParent;
result = nsIEditorSupport::GetChildOffset(blockParentElement, grandParent, offsetInParent);
PRUint32 childCount;
childNodes->GetLength(&childCount);
PRInt32 i=childCount-1;
for ( ; ((NS_SUCCEEDED(result)) && (0<=i)); i--)
{
nsCOMPtr<nsIDOMNode> childNode;
result = childNodes->Item(i, getter_AddRefs(childNode));
if ((NS_SUCCEEDED(result)) && (childNode))
{
result = nsTextEditor::DeleteNode(childNode);
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::InsertNode(childNode, grandParent, offsetInParent);
}
}
}
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::DeleteNode(blockParentElement);
}
}
}
result = nsTextEditor::GetBlockParent(startParent, getter_AddRefs(blockParentElement));
}
}
}
} }
} }
nsEditor::EndTransaction(); nsEditor::EndTransaction();
@ -881,11 +920,93 @@ nsHTMLEditor::RemoveBlockParent()
return result; return result;
} }
NS_IMETHODIMP
nsHTMLEditor::RemoveParagraphStyleFromRange(nsIDOMRange *aRange)
{
if (!aRange) { return NS_ERROR_NULL_POINTER; }
nsresult result;
nsISupportsArray *blockSections;
result = NS_NewISupportsArray(&blockSections);
if ((NS_SUCCEEDED(result)) && blockSections)
{
result = GetBlockSectionsForRange(aRange, blockSections);
if (NS_SUCCEEDED(result))
{
nsIDOMRange *subRange;
subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
while (subRange && (NS_SUCCEEDED(result)))
{
result = RemoveParagraphStyleFromBlockContent(subRange);
NS_RELEASE(subRange);
blockSections->RemoveElementAt(0);
subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
}
}
NS_RELEASE(blockSections);
}
return result;
}
NS_IMETHODIMP
nsHTMLEditor::RemoveParagraphStyleFromBlockContent(nsIDOMRange *aRange)
{
if (!aRange) { return NS_ERROR_NULL_POINTER; }
nsresult result;
nsCOMPtr<nsIDOMNode>startParent;
aRange->GetStartParent(getter_AddRefs(startParent));
nsCOMPtr<nsIDOMElement>blockParentElement;
result = nsTextEditor::GetBlockParent(startParent, getter_AddRefs(blockParentElement));
while ((NS_SUCCEEDED(result)) && blockParentElement)
{
nsAutoString blockParentTag;
blockParentElement->GetTagName(blockParentTag);
PRBool isSubordinateBlock;
IsSubordinateBlock(blockParentTag, isSubordinateBlock);
if (PR_FALSE==isSubordinateBlock) {
break;
}
else
{
// go through list backwards so deletes don't interfere with the iteration
nsCOMPtr<nsIDOMNodeList> childNodes;
result = blockParentElement->GetChildNodes(getter_AddRefs(childNodes));
if ((NS_SUCCEEDED(result)) && (childNodes))
{
nsCOMPtr<nsIDOMNode>grandParent;
blockParentElement->GetParentNode(getter_AddRefs(grandParent));
PRInt32 offsetInParent;
result = GetChildOffset(blockParentElement, grandParent, offsetInParent);
PRUint32 childCount;
childNodes->GetLength(&childCount);
PRInt32 i=childCount-1;
for ( ; ((NS_SUCCEEDED(result)) && (0<=i)); i--)
{
nsCOMPtr<nsIDOMNode> childNode;
result = childNodes->Item(i, getter_AddRefs(childNode));
if ((NS_SUCCEEDED(result)) && (childNode))
{
result = nsTextEditor::DeleteNode(childNode);
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::InsertNode(childNode, grandParent, offsetInParent);
}
}
}
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::DeleteNode(blockParentElement);
}
}
}
result = nsTextEditor::GetBlockParent(startParent, getter_AddRefs(blockParentElement));
}
return result;
}
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLEditor::RemoveParent(const nsString &aParentTag) nsHTMLEditor::RemoveParent(const nsString &aParentTag)
{ {
if (gNoisy) { if (gNoisy) {
printf("---------- nsHTMLEditor::RemoveParent %s----------\n", aParentTag); printf("---------- nsHTMLEditor::RemoveParagraphStyle ----------\n");
} }
nsresult result=NS_ERROR_NOT_INITIALIZED; nsresult result=NS_ERROR_NOT_INITIALIZED;
@ -904,68 +1025,7 @@ nsHTMLEditor::RemoveParent(const nsString &aParentTag)
if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem))
{ {
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) ); nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
nsCOMPtr<nsIDOMNode>commonParent; result = RemoveParentFromRange(aParentTag, range);
result = range->GetCommonParent(getter_AddRefs(commonParent));
if ((NS_SUCCEEDED(result)) && commonParent)
{
PRInt32 startOffset, endOffset;
range->GetStartOffset(&startOffset);
range->GetEndOffset(&endOffset);
nsCOMPtr<nsIDOMNode> startParent; nsCOMPtr<nsIDOMNode> endParent;
range->GetStartParent(getter_AddRefs(startParent));
range->GetEndParent(getter_AddRefs(endParent));
if (startParent.get()==endParent.get())
{ // the range is entirely contained within a single node
nsCOMPtr<nsIDOMNode>parentNode;
nsCOMPtr<nsIDOMElement>parentElement;
result = startParent->GetParentNode(getter_AddRefs(parentNode));
while ((NS_SUCCEEDED(result)) && parentNode)
{
parentElement = do_QueryInterface(parentNode);
nsAutoString childTag; // leave as empty string
nsAutoString parentTag;
parentElement->GetTagName(parentTag);
PRBool canContain;
CanContainBlock(childTag, parentTag, canContain);
if (aParentTag.EqualsIgnoreCase(parentTag))
{
// go through list backwards so deletes don't interfere with the iteration
nsCOMPtr<nsIDOMNodeList> childNodes;
result = parentElement->GetChildNodes(getter_AddRefs(childNodes));
if ((NS_SUCCEEDED(result)) && (childNodes))
{
nsCOMPtr<nsIDOMNode>grandParent;
parentElement->GetParentNode(getter_AddRefs(grandParent));
PRInt32 offsetInParent;
result = nsIEditorSupport::GetChildOffset(parentElement, grandParent, offsetInParent);
PRUint32 childCount;
childNodes->GetLength(&childCount);
PRInt32 i=childCount-1;
for ( ; ((NS_SUCCEEDED(result)) && (0<=i)); i--)
{
nsCOMPtr<nsIDOMNode> childNode;
result = childNodes->Item(i, getter_AddRefs(childNode));
if ((NS_SUCCEEDED(result)) && (childNode))
{
result = nsTextEditor::DeleteNode(childNode);
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::InsertNode(childNode, grandParent, offsetInParent);
}
}
}
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::DeleteNode(parentElement);
}
}
break;
}
else if (PR_TRUE==canContain) { // hit a subdoc, terminate?
break;
}
result = parentElement->GetParentNode(getter_AddRefs(parentNode));
}
}
}
} }
} }
nsEditor::EndTransaction(); nsEditor::EndTransaction();
@ -973,6 +1033,92 @@ nsHTMLEditor::RemoveParent(const nsString &aParentTag)
return result; return result;
} }
NS_IMETHODIMP
nsHTMLEditor::RemoveParentFromRange(const nsString &aParentTag, nsIDOMRange *aRange)
{
if (!aRange) { return NS_ERROR_NULL_POINTER; }
nsresult result;
nsISupportsArray *blockSections;
result = NS_NewISupportsArray(&blockSections);
if ((NS_SUCCEEDED(result)) && blockSections)
{
result = GetBlockSectionsForRange(aRange, blockSections);
if (NS_SUCCEEDED(result))
{
nsIDOMRange *subRange;
subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
while (subRange && (NS_SUCCEEDED(result)))
{
result = RemoveParentFromBlockContent(aParentTag, subRange);
NS_RELEASE(subRange);
blockSections->RemoveElementAt(0);
subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
}
}
NS_RELEASE(blockSections);
}
return result;
}
NS_IMETHODIMP
nsHTMLEditor::RemoveParentFromBlockContent(const nsString &aParentTag, nsIDOMRange *aRange)
{
if (!aRange) { return NS_ERROR_NULL_POINTER; }
nsresult result;
nsCOMPtr<nsIDOMNode>startParent;
result = aRange->GetStartParent(getter_AddRefs(startParent));
if ((NS_SUCCEEDED(result)) && startParent)
{
nsCOMPtr<nsIDOMNode>parentNode;
nsCOMPtr<nsIDOMElement>parentElement;
result = startParent->GetParentNode(getter_AddRefs(parentNode));
while ((NS_SUCCEEDED(result)) && parentNode)
{
parentElement = do_QueryInterface(parentNode);
nsAutoString parentTag;
parentElement->GetTagName(parentTag);
PRBool isRoot;
IsRootTag(parentTag, isRoot);
if (aParentTag.EqualsIgnoreCase(parentTag))
{
// go through list backwards so deletes don't interfere with the iteration
nsCOMPtr<nsIDOMNodeList> childNodes;
result = parentElement->GetChildNodes(getter_AddRefs(childNodes));
if ((NS_SUCCEEDED(result)) && (childNodes))
{
nsCOMPtr<nsIDOMNode>grandParent;
parentElement->GetParentNode(getter_AddRefs(grandParent));
PRInt32 offsetInParent;
result = GetChildOffset(parentElement, grandParent, offsetInParent);
PRUint32 childCount;
childNodes->GetLength(&childCount);
PRInt32 i=childCount-1;
for ( ; ((NS_SUCCEEDED(result)) && (0<=i)); i--)
{
nsCOMPtr<nsIDOMNode> childNode;
result = childNodes->Item(i, getter_AddRefs(childNode));
if ((NS_SUCCEEDED(result)) && (childNode))
{
result = nsTextEditor::DeleteNode(childNode);
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::InsertNode(childNode, grandParent, offsetInParent);
}
}
}
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::DeleteNode(parentElement);
}
}
break;
}
else if (PR_TRUE==isRoot) { // hit a local root node, terminate loop
break;
}
result = parentElement->GetParentNode(getter_AddRefs(parentNode));
}
}
return result;
}
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLEditor::InsertLink(nsString& aURL) nsHTMLEditor::InsertLink(nsString& aURL)
@ -1331,6 +1477,62 @@ nsHTMLEditor::InsertElement(nsIDOMElement* aElement, PRBool aDeleteSelection, ns
return result; return result;
} }
NS_IMETHODIMP
nsHTMLEditor::IsRootTag(nsString &aTag, PRBool &aIsTag)
{
static nsAutoString bodyTag = "body";
static nsAutoString tdTag = "td";
static nsAutoString thTag = "th";
static nsAutoString captionTag = "caption";
if (PR_TRUE==aTag.EqualsIgnoreCase(bodyTag) ||
PR_TRUE==aTag.EqualsIgnoreCase(tdTag) ||
PR_TRUE==aTag.EqualsIgnoreCase(thTag) ||
PR_TRUE==aTag.EqualsIgnoreCase(captionTag) )
{
aIsTag = PR_TRUE;
}
else {
aIsTag = PR_FALSE;
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLEditor::IsSubordinateBlock(nsString &aTag, PRBool &aIsTag)
{
static nsAutoString p = "p";
static nsAutoString h1 = "h1";
static nsAutoString h2 = "h2";
static nsAutoString h3 = "h3";
static nsAutoString h4 = "h4";
static nsAutoString h5 = "h5";
static nsAutoString h6 = "h6";
static nsAutoString address = "address";
static nsAutoString pre = "pre";
static nsAutoString li = "li";
static nsAutoString dt = "dt";
static nsAutoString dd = "dd";
if (PR_TRUE==aTag.EqualsIgnoreCase(p) ||
PR_TRUE==aTag.EqualsIgnoreCase(h1) ||
PR_TRUE==aTag.EqualsIgnoreCase(h2) ||
PR_TRUE==aTag.EqualsIgnoreCase(h3) ||
PR_TRUE==aTag.EqualsIgnoreCase(h4) ||
PR_TRUE==aTag.EqualsIgnoreCase(h5) ||
PR_TRUE==aTag.EqualsIgnoreCase(h6) ||
PR_TRUE==aTag.EqualsIgnoreCase(address) ||
PR_TRUE==aTag.EqualsIgnoreCase(pre) ||
PR_TRUE==aTag.EqualsIgnoreCase(li) ||
PR_TRUE==aTag.EqualsIgnoreCase(dt) ||
PR_TRUE==aTag.EqualsIgnoreCase(dd) )
{
aIsTag = PR_TRUE;
}
else {
aIsTag = PR_FALSE;
}
return NS_OK;
}
NS_IMETHODIMP nsHTMLEditor::BeginComposition(void) NS_IMETHODIMP nsHTMLEditor::BeginComposition(void)
{ {
return nsTextEditor::BeginComposition(); return nsTextEditor::BeginComposition();
@ -1344,4 +1546,4 @@ NS_IMETHODIMP nsHTMLEditor::EndComposition(void)
NS_IMETHODIMP nsHTMLEditor::SetCompositionString(const nsString& aCompositionString) NS_IMETHODIMP nsHTMLEditor::SetCompositionString(const nsString& aCompositionString)
{ {
return nsTextEditor::SetCompositionString(aCompositionString); return nsTextEditor::SetCompositionString(aCompositionString);
} }

Просмотреть файл

@ -107,7 +107,7 @@ public:
NS_IMETHOD GetParagraphStyle(nsStringArray *aTagList); NS_IMETHOD GetParagraphStyle(nsStringArray *aTagList);
NS_IMETHOD AddBlockParent(nsString& aParentTag); NS_IMETHOD AddBlockParent(nsString& aParentTag);
NS_IMETHOD ReplaceBlockParent(nsString& aParentTag); NS_IMETHOD ReplaceBlockParent(nsString& aParentTag);
NS_IMETHOD RemoveBlockParent(); NS_IMETHOD RemoveParagraphStyle();
NS_IMETHOD RemoveParent(const nsString &aParentTag); NS_IMETHOD RemoveParent(const nsString &aParentTag);
NS_IMETHOD InsertLink(nsString& aURL); NS_IMETHOD InsertLink(nsString& aURL);
@ -163,8 +163,22 @@ protected:
nsString &aParentTag, nsString &aParentTag,
BlockTransformationType aTranformation); BlockTransformationType aTranformation);
NS_IMETHOD RemoveParagraphStyleFromRange(nsIDOMRange *aRange);
NS_IMETHOD RemoveParagraphStyleFromBlockContent(nsIDOMRange *aRange);
NS_IMETHOD RemoveParentFromRange(const nsString &aParentTag, nsIDOMRange *aRange);
NS_IMETHOD RemoveParentFromBlockContent(const nsString &aParentTag, nsIDOMRange *aRange);
NS_IMETHOD CanContainBlock(nsString &aBlockChild, nsString &aBlockParent, PRBool &aCanContain); NS_IMETHOD CanContainBlock(nsString &aBlockChild, nsString &aBlockParent, PRBool &aCanContain);
NS_IMETHOD IsRootTag(nsString &aTag, PRBool &aIsTag);
NS_IMETHOD IsSubordinateBlock(nsString &aTag, PRBool &aIsTag);
// EVENT LISTENERS AND COMMAND ROUTING NEEDS WORK // EVENT LISTENERS AND COMMAND ROUTING NEEDS WORK
// For now, the listners are tied to the nsTextEditor class // For now, the listners are tied to the nsTextEditor class
// //

Просмотреть файл

@ -73,6 +73,7 @@ SUP places text in superscript style
// block tags // block tags
static nsIAtom *blockquote; static nsIAtom *blockquote;
static nsIAtom *br;
static nsIAtom *h1; static nsIAtom *h1;
static nsIAtom *h2; static nsIAtom *h2;

Просмотреть файл

@ -18,6 +18,7 @@
#include "nsTextEditRules.h" #include "nsTextEditRules.h"
#include "nsTextEditor.h" #include "nsTextEditor.h"
#include "nsEditor.h"
#include "PlaceholderTxn.h" #include "PlaceholderTxn.h"
#include "InsertTextTxn.h" #include "InsertTextTxn.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
@ -31,69 +32,8 @@
#include "nsIContent.h" #include "nsIContent.h"
#include "nsIEditProperty.h" #include "nsIEditProperty.h"
const static char* kMOZEditorBogusNodeAttr="MOZ_EDITOR_BOGUS_NODE";
const static char* kMOZEditorBogusNodeValue="TRUE";
static NS_DEFINE_IID(kPlaceholderTxnIID, PLACEHOLDER_TXN_IID); static NS_DEFINE_IID(kPlaceholderTxnIID, PLACEHOLDER_TXN_IID);
/********************************************************
* Helper Functions
********************************************************/
PRBool nsTextEditRules::NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag)
{
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(aNode);
if (element)
{
nsAutoString tag;
element->GetTagName(tag);
if (tag.Equals(aTag->GetUnicode()))
{
return PR_TRUE;
}
}
return PR_FALSE;
}
PRBool nsTextEditRules::IsEditable(nsIDOMNode *aNode)
{
if (!aNode) return PR_FALSE;
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(aNode);
if (element)
{
nsAutoString att(kMOZEditorBogusNodeAttr);
nsAutoString val;
(void)element->GetAttribute(att, val);
if (val.Equals(kMOZEditorBogusNodeValue)) {
return PR_FALSE;
}
else {
return PR_TRUE;
}
}
else
{
nsCOMPtr<nsIDOMCharacterData>text;
text = do_QueryInterface(aNode);
if (text)
{
nsAutoString data;
text->GetData(data);
if (0==data.Length()) {
return PR_FALSE;
}
if ('\n'==data.CharAt(0)) {
return PR_FALSE;
}
else {
return PR_TRUE;
}
}
}
return PR_TRUE;
}
/******************************************************** /********************************************************
@ -437,7 +377,7 @@ nsTextEditRules::InsertStyleNode(nsIDOMNode *aNode,
nsCOMPtr<nsIDOMNode>parent; nsCOMPtr<nsIDOMNode>parent;
aNode->GetParentNode(getter_AddRefs(parent)); aNode->GetParentNode(getter_AddRefs(parent));
PRInt32 offsetInParent; PRInt32 offsetInParent;
nsIEditorSupport::GetChildOffset(aNode, parent, offsetInParent); nsEditor::GetChildOffset(aNode, parent, offsetInParent);
nsAutoString tag; nsAutoString tag;
aTag->ToString(tag); aTag->ToString(tag);
result = mEditor->CreateNode(tag, parent, offsetInParent, aNewNode); result = mEditor->CreateNode(tag, parent, offsetInParent, aNewNode);
@ -563,7 +503,7 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection, nsresult aResul
result = bodyNode->GetFirstChild(getter_AddRefs(bodyChild)); result = bodyNode->GetFirstChild(getter_AddRefs(bodyChild));
while ((NS_SUCCEEDED(result)) && bodyChild) while ((NS_SUCCEEDED(result)) && bodyChild)
{ {
if (PR_TRUE==IsEditable(bodyChild)) if (PR_TRUE==nsEditor::IsEditable(bodyChild))
{ {
needsBogusContent = PR_FALSE; needsBogusContent = PR_FALSE;
break; break;
@ -599,8 +539,8 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection, nsresult aResul
newPElement = do_QueryInterface(mBogusNode); newPElement = do_QueryInterface(mBogusNode);
if (newPElement) if (newPElement)
{ {
nsAutoString att(kMOZEditorBogusNodeAttr); nsAutoString att(nsEditor::kMOZEditorBogusNodeAttr);
nsAutoString val(kMOZEditorBogusNodeValue); nsAutoString val(nsEditor::kMOZEditorBogusNodeValue);
newPElement->SetAttribute(att, val); newPElement->SetAttribute(att, val);
} }
} }
@ -706,10 +646,10 @@ nsTextEditRules:: DidUndo(nsIDOMSelection *aSelection, nsresult aResult)
element = do_QueryInterface(node); element = do_QueryInterface(node);
if (element) if (element)
{ {
nsAutoString att(kMOZEditorBogusNodeAttr); nsAutoString att(nsEditor::kMOZEditorBogusNodeAttr);
nsAutoString val; nsAutoString val;
(void)element->GetAttribute(att, val); (void)element->GetAttribute(att, val);
if (val.Equals(kMOZEditorBogusNodeValue)) { if (val.Equals(nsEditor::kMOZEditorBogusNodeValue)) {
mBogusNode = do_QueryInterface(element); mBogusNode = do_QueryInterface(element);
} }
} }
@ -752,10 +692,10 @@ nsTextEditRules::DidRedo(nsIDOMSelection *aSelection, nsresult aResult)
element = do_QueryInterface(node); element = do_QueryInterface(node);
if (element) if (element)
{ {
nsAutoString att(kMOZEditorBogusNodeAttr); nsAutoString att(nsEditor::kMOZEditorBogusNodeAttr);
nsAutoString val; nsAutoString val;
(void)element->GetAttribute(att, val); (void)element->GetAttribute(att, val);
if (val.Equals(kMOZEditorBogusNodeValue)) { if (val.Equals(nsEditor::kMOZEditorBogusNodeValue)) {
mBogusNode = do_QueryInterface(element); mBogusNode = do_QueryInterface(element);
} }
} }

Просмотреть файл

@ -85,8 +85,6 @@ protected:
nsresult DidRedo(nsIDOMSelection *aSelection, nsresult aResult); nsresult DidRedo(nsIDOMSelection *aSelection, nsresult aResult);
// helper functions // helper functions
static PRBool NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag);
static PRBool IsEditable(nsIDOMNode *aNode);
/** insert aNode into a new style node of type aTag. /** insert aNode into a new style node of type aTag.
* aSelection is optional. If provided, aSelection is set to (aNode, 0) * aSelection is optional. If provided, aSelection is set to (aNode, 0)

Просмотреть файл

@ -17,7 +17,6 @@
*/ */
#include "nsTextEditor.h" #include "nsTextEditor.h"
#include "nsIEditorSupport.h"
#include "nsEditorEventListeners.h" #include "nsEditorEventListeners.h"
#include "nsIEditProperty.h" #include "nsIEditProperty.h"
#include "nsEditProperty.h" // temporary, to get html atoms #include "nsEditProperty.h" // temporary, to get html atoms
@ -96,7 +95,7 @@ static NS_DEFINE_IID(kIInputStreamIID, NS_IINPUTSTREAM_IID);
static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID); static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID);
#ifdef NS_DEBUG #ifdef NS_DEBUG
static PRBool gNoisy = PR_FALSE; static PRBool gNoisy = PR_TRUE;
#else #else
static const PRBool gNoisy = PR_FALSE; static const PRBool gNoisy = PR_FALSE;
#endif #endif
@ -601,7 +600,7 @@ void nsTextEditor::IsTextPropertySetByContent(nsIDOMNode *aNode,
{ {
nsString tag; nsString tag;
element->GetTagName(tag); element->GetTagName(tag);
if (propName.Equals(tag)) if (propName.EqualsIgnoreCase(tag))
{ {
PRBool found = PR_FALSE; PRBool found = PR_FALSE;
if (aAttribute) if (aAttribute)
@ -613,7 +612,7 @@ void nsTextEditor::IsTextPropertySetByContent(nsIDOMNode *aNode,
if (!aValue) { if (!aValue) {
found = PR_TRUE; found = PR_TRUE;
} }
else if (aValue->Equals(value)) { else if (aValue->EqualsIgnoreCase(value)) {
found = PR_TRUE; found = PR_TRUE;
} }
else { // we found the prop with the attribute, but the value doesn't match else { // we found the prop with the attribute, but the value doesn't match
@ -1243,7 +1242,7 @@ NS_IMETHODIMP nsTextEditor::MoveContentOfNodeIntoNewParent(nsIDOMNode *aNode,
result = nsEditor::DeleteNode(aNewParentNode); result = nsEditor::DeleteNode(aNewParentNode);
if (NS_SUCCEEDED(result)) if (NS_SUCCEEDED(result))
{ // must get child offset AFTER delete of aNewParentNode! { // must get child offset AFTER delete of aNewParentNode!
result = nsIEditorSupport::GetChildOffset(aNode, parentNode, offsetInParent); result = GetChildOffset(aNode, parentNode, offsetInParent);
if (NS_SUCCEEDED(result)) if (NS_SUCCEEDED(result))
{ {
result = nsEditor::InsertNode(aNewParentNode, parentNode, offsetInParent); result = nsEditor::InsertNode(aNewParentNode, parentNode, offsetInParent);
@ -1278,298 +1277,6 @@ NS_IMETHODIMP nsTextEditor::MoveContentOfNodeIntoNewParent(nsIDOMNode *aNode,
return result; return result;
} }
// returns the number of things inside aNode.
// If aNode is text, returns number of characters. If not, returns number of children nodes.
NS_IMETHODIMP nsTextEditor::GetLengthOfDOMNode(nsIDOMNode *aNode, PRUint32 &aCount) const
{
aCount = 0;
if (!aNode) { return NS_ERROR_NULL_POINTER; }
nsresult result=NS_OK;
nsCOMPtr<nsIDOMCharacterData>nodeAsChar;
nodeAsChar = do_QueryInterface(aNode);
if (nodeAsChar) {
nodeAsChar->GetLength(&aCount);
}
else
{
PRBool hasChildNodes;
aNode->HasChildNodes(&hasChildNodes);
if (PR_TRUE==hasChildNodes)
{
nsCOMPtr<nsIDOMNodeList>nodeList;
result = aNode->GetChildNodes(getter_AddRefs(nodeList));
if (NS_SUCCEEDED(result) && nodeList) {
nodeList->GetLength(&aCount);
}
}
}
return result;
}
// content-based inline vs. block query
NS_IMETHODIMP
nsTextEditor::IsNodeInline(nsIDOMNode *aNode, PRBool &aIsInline) const
{
// this is a content-based implementation
if (!aNode) { return NS_ERROR_NULL_POINTER; }
nsresult result;
aIsInline = PR_FALSE;
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(aNode);
if (element)
{
nsAutoString tag;
result = element->GetTagName(tag);
if (NS_SUCCEEDED(result))
{
nsIAtom *tagAtom = NS_NewAtom(tag);
if (!tagAtom) { return NS_ERROR_NULL_POINTER; }
if (tagAtom==nsIEditProperty::a ||
tagAtom==nsIEditProperty::b ||
tagAtom==nsIEditProperty::big ||
tagAtom==nsIEditProperty::font ||
tagAtom==nsIEditProperty::i ||
tagAtom==nsIEditProperty::span ||
tagAtom==nsIEditProperty::small ||
tagAtom==nsIEditProperty::strike ||
tagAtom==nsIEditProperty::sub ||
tagAtom==nsIEditProperty::sup ||
tagAtom==nsIEditProperty::tt ||
tagAtom==nsIEditProperty::u )
{
aIsInline = PR_TRUE;
}
}
}
return NS_OK;
}
NS_IMETHODIMP
nsTextEditor::GetBlockParent(nsIDOMNode *aNode, nsIDOMElement **aBlockParent) const
{
nsresult result = NS_OK;
if (!aBlockParent) {return NS_ERROR_NULL_POINTER;}
*aBlockParent = nsnull;
nsCOMPtr<nsIDOMNode>parent;
nsCOMPtr<nsIDOMNode>temp;
result = aNode->GetParentNode(getter_AddRefs(parent));
while (NS_SUCCEEDED(result) && parent)
{
PRBool isInline;
result = IsNodeInline(parent, isInline);
if (PR_FALSE==isInline)
{
parent->QueryInterface(nsIDOMElement::GetIID(), (void**)aBlockParent);
break;
}
result = parent->GetParentNode(getter_AddRefs(temp));
parent = do_QueryInterface(temp);
}
if (gNoisy) { printf("GetBlockParent for %p returning parent %p\n", aNode, *aBlockParent); }
return result;
}
NS_IMETHODIMP
nsTextEditor::GetBlockDelimitedContent(nsIDOMNode *aChild,
nsIDOMNode **aLeftNode,
nsIDOMNode **aRightNode) const
{
nsresult result = NS_OK;
if (!aChild || !aLeftNode || !aRightNode) {return NS_ERROR_NULL_POINTER;}
*aLeftNode = aChild;
*aRightNode = aChild;
nsCOMPtr<nsIDOMNode>sibling;
result = aChild->GetPreviousSibling(getter_AddRefs(sibling));
while ((NS_SUCCEEDED(result)) && sibling)
{
PRBool isInline;
IsNodeInline(sibling, isInline);
if (PR_FALSE==isInline)
{
nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
if (!nodeAsText) {
break;
}
}
*aLeftNode = sibling;
result = (*aLeftNode)->GetPreviousSibling(getter_AddRefs(sibling));
}
NS_ADDREF((*aLeftNode));
// now do the right side
result = aChild->GetNextSibling(getter_AddRefs(sibling));
while ((NS_SUCCEEDED(result)) && sibling)
{
PRBool isInline;
IsNodeInline(sibling, isInline);
if (PR_FALSE==isInline)
{
nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
if (!nodeAsText) {
break;
}
}
*aRightNode = sibling;
result = (*aRightNode)->GetNextSibling(getter_AddRefs(sibling));
}
NS_ADDREF((*aRightNode));
if (gNoisy) { printf("GetBlockDelimitedContent returning %p %p\n",
(*aLeftNode), (*aRightNode)); }
return result;
}
NS_IMETHODIMP
nsTextEditor::GetBlockRanges(nsIDOMRange *aRange, nsISupportsArray *aSubRanges) const
{
if (!aRange || !aSubRanges) {return NS_ERROR_NULL_POINTER;}
nsresult result;
nsCOMPtr<nsIContentIterator>iter;
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
kIContentIteratorIID, getter_AddRefs(iter));
if ((NS_SUCCEEDED(result)) && iter)
{
nsCOMPtr<nsIDOMRange> lastRange;
iter->Init(aRange);
nsCOMPtr<nsIContent> currentContent;
iter->CurrentNode(getter_AddRefs(currentContent));
while (NS_COMFALSE == iter->IsDone())
{
nsCOMPtr<nsIDOMNode>currentNode = do_QueryInterface(currentContent);
if (currentNode)
{
PRBool isInlineOrText;
result = IsNodeInline(currentNode, isInlineOrText);
if (PR_FALSE==isInlineOrText)
{
PRUint16 nodeType;
currentNode->GetNodeType(&nodeType);
if (nsIDOMNode::TEXT_NODE == nodeType) {
isInlineOrText = PR_TRUE;
}
}
if (PR_TRUE==isInlineOrText)
{
nsCOMPtr<nsIDOMNode>leftNode;
nsCOMPtr<nsIDOMNode>rightNode;
result = GetBlockDelimitedContent(currentNode,
getter_AddRefs(leftNode),
getter_AddRefs(rightNode));
if (gNoisy) {printf("currentNode %p has block content (%p,%p)\n", currentNode.get(), leftNode.get(), rightNode.get());}
if ((NS_SUCCEEDED(result)) && leftNode && rightNode)
{
// add range to the list if it doesn't overlap with the previous range
PRBool addRange=PR_TRUE;
if (lastRange)
{
nsCOMPtr<nsIDOMNode> lastStartNode;
nsCOMPtr<nsIDOMElement> blockParentOfLastStartNode;
lastRange->GetStartParent(getter_AddRefs(lastStartNode));
result = GetBlockParent(lastStartNode, getter_AddRefs(blockParentOfLastStartNode));
if ((NS_SUCCEEDED(result)) && blockParentOfLastStartNode)
{
if (gNoisy) {printf("lastStartNode %p has block parent %p\n", lastStartNode.get(), blockParentOfLastStartNode.get());}
nsCOMPtr<nsIDOMElement> blockParentOfLeftNode;
result = GetBlockParent(leftNode, getter_AddRefs(blockParentOfLeftNode));
if ((NS_SUCCEEDED(result)) && blockParentOfLeftNode)
{
if (gNoisy) {printf("leftNode %p has block parent %p\n", leftNode.get(), blockParentOfLeftNode.get());}
if (blockParentOfLastStartNode==blockParentOfLeftNode) {
addRange = PR_FALSE;
}
}
}
}
if (PR_TRUE==addRange)
{
if (gNoisy) {printf("adding range, setting lastRange with start node %p\n", leftNode.get());}
nsCOMPtr<nsIDOMRange> range;
result = nsComponentManager::CreateInstance(kCRangeCID, nsnull,
kIDOMRangeIID, getter_AddRefs(range));
if ((NS_SUCCEEDED(result)) && range)
{ // initialize the range
range->SetStart(leftNode, 0);
range->SetEnd(rightNode, 0);
aSubRanges->AppendElement(range);
lastRange = do_QueryInterface(range);
}
}
}
}
}
/* do not check result here, and especially do not return the result code.
* we rely on iter->IsDone to tell us when the iteration is complete
*/
iter->Next();
iter->CurrentNode(getter_AddRefs(currentContent));
}
}
return result;
}
NS_IMETHODIMP
nsTextEditor::IntermediateNodesAreInline(nsIDOMRange *aRange,
nsIDOMNode *aStartNode,
PRInt32 aStartOffset,
nsIDOMNode *aEndNode,
PRInt32 aEndOffset,
PRBool &aResult) const
{
aResult = PR_TRUE; // init out param. we assume the condition is true unless we find a node that violates it
if (!aStartNode || !aEndNode || !aRange) { return NS_ERROR_NULL_POINTER; }
nsCOMPtr<nsIContentIterator>iter;
nsresult result;
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
kIContentIteratorIID, getter_AddRefs(iter));
//XXX: maybe CreateInstance is expensive, and I should keep around a static iter?
// as long as this method can't be called recursively or re-entrantly!
if ((NS_SUCCEEDED(result)) && iter)
{
nsCOMPtr<nsIContent>startContent;
startContent = do_QueryInterface(aStartNode);
nsCOMPtr<nsIContent>endContent;
endContent = do_QueryInterface(aEndNode);
if (startContent && endContent)
{
iter->Init(aRange);
nsCOMPtr<nsIContent> content;
iter->CurrentNode(getter_AddRefs(content));
while (NS_COMFALSE == iter->IsDone())
{
if ((content.get() != startContent.get()) &&
(content.get() != endContent.get()))
{
nsCOMPtr<nsIDOMNode>currentNode;
currentNode = do_QueryInterface(content);
PRBool isInline=PR_FALSE;
IsNodeInline(currentNode, isInline);
if (PR_FALSE==isInline)
{
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
nodeAsText = do_QueryInterface(currentNode);
if (!nodeAsText) // text nodes don't count in this check, so ignore them
{
aResult = PR_FALSE;
break;
}
}
}
/* do not check result here, and especially do not return the result code.
* we rely on iter->IsDone to tell us when the iteration is complete
*/
iter->Next();
iter->CurrentNode(getter_AddRefs(content));
}
}
}
return result;
}
/* this should only get called if the only intervening nodes are inline style nodes */ /* this should only get called if the only intervening nodes are inline style nodes */
NS_IMETHODIMP NS_IMETHODIMP
nsTextEditor::SetTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode, nsTextEditor::SetTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode,
@ -1641,7 +1348,7 @@ NS_IMETHODIMP nsTextEditor::MoveContiguousContentIntoNewParent(nsIDOMNode *aSta
{ {
PRInt32 offsetInParent; PRInt32 offsetInParent;
if (newLeftNode) { if (newLeftNode) {
result = nsIEditorSupport::GetChildOffset(newLeftNode, aGrandParentNode, offsetInParent); result = GetChildOffset(newLeftNode, aGrandParentNode, offsetInParent);
} }
else { else {
offsetInParent = -1; // relies on +1 below in call to CreateNode offsetInParent = -1; // relies on +1 below in call to CreateNode
@ -1903,10 +1610,10 @@ NS_IMETHODIMP nsTextEditor::RemoveTextPropertiesForNode(nsIDOMNode *aNode,
if (gNoisy) { printf("* parent has tag %s\n", tag.ToNewCString()); } // XXX leak! if (gNoisy) { printf("* parent has tag %s\n", tag.ToNewCString()); } // XXX leak!
if (NS_SUCCEEDED(result)) if (NS_SUCCEEDED(result))
{ {
if (PR_FALSE==tag.Equals(aPropName->GetUnicode())) if (PR_FALSE==tag.EqualsIgnoreCase(aPropName->GetUnicode()))
{ {
PRInt32 offsetInParent; PRInt32 offsetInParent;
result = nsIEditorSupport::GetChildOffset(newMiddleNode, parent, offsetInParent); result = GetChildOffset(newMiddleNode, parent, offsetInParent);
if (NS_SUCCEEDED(result)) if (NS_SUCCEEDED(result))
{ {
if (0!=offsetInParent) { if (0!=offsetInParent) {
@ -1947,7 +1654,7 @@ NS_IMETHODIMP nsTextEditor::RemoveTextPropertiesForNode(nsIDOMNode *aNode,
{ {
if (gNoisy) { printf("* this is the style node\n");} if (gNoisy) { printf("* this is the style node\n");}
PRInt32 offsetInParent; PRInt32 offsetInParent;
result = nsIEditorSupport::GetChildOffset(newMiddleNode, parent, offsetInParent); result = GetChildOffset(newMiddleNode, parent, offsetInParent);
if (NS_SUCCEEDED(result)) if (NS_SUCCEEDED(result))
{ {
nsCOMPtr<nsIDOMNodeList>childNodes; nsCOMPtr<nsIDOMNodeList>childNodes;
@ -1980,7 +1687,7 @@ NS_IMETHODIMP nsTextEditor::RemoveTextPropertiesForNode(nsIDOMNode *aNode,
{ // promote the selection to the grandparent { // promote the selection to the grandparent
// first, determine the child's position in it's parent // first, determine the child's position in it's parent
PRInt32 childPositionInParent; PRInt32 childPositionInParent;
nsIEditorSupport::GetChildOffset(newMiddleNode, parent, childPositionInParent); GetChildOffset(newMiddleNode, parent, childPositionInParent);
// compare childPositionInParent to the number of children in parent // compare childPositionInParent to the number of children in parent
PRUint32 count=0; PRUint32 count=0;
nsCOMPtr<nsIDOMNodeList>childNodes; nsCOMPtr<nsIDOMNodeList>childNodes;
@ -2004,7 +1711,7 @@ NS_IMETHODIMP nsTextEditor::RemoveTextPropertiesForNode(nsIDOMNode *aNode,
if (NS_SUCCEEDED(result)) if (NS_SUCCEEDED(result))
{ {
PRInt32 position; PRInt32 position;
result = nsIEditorSupport::GetChildOffset(parent, grandParent, position); result = GetChildOffset(parent, grandParent, position);
if (NS_SUCCEEDED(result)) if (NS_SUCCEEDED(result))
{ {
if (PR_TRUE==insertAfter) if (PR_TRUE==insertAfter)
@ -2242,7 +1949,7 @@ nsTextEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStar
{ {
nsString tag; nsString tag;
element->GetTagName(tag); element->GetTagName(tag);
if (propName.Equals(tag)) if (propName.EqualsIgnoreCase(tag))
{ {
if (-1==nodeList.IndexOf(content.get())) { if (-1==nodeList.IndexOf(content.get())) {
nodeList.AppendElement((void *)(content.get())); nodeList.AppendElement((void *)(content.get()));
@ -2272,7 +1979,7 @@ nsTextEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStar
if (NS_SUCCEEDED(result) && parentNode) if (NS_SUCCEEDED(result) && parentNode)
{ {
PRInt32 position; PRInt32 position;
result = nsIEditorSupport::GetChildOffset(styleNode, parentNode, position); result = GetChildOffset(styleNode, parentNode, position);
if (NS_SUCCEEDED(result)) if (NS_SUCCEEDED(result))
{ {
nsCOMPtr<nsIDOMNode>previousSiblingNode; nsCOMPtr<nsIDOMNode>previousSiblingNode;

Просмотреть файл

@ -145,39 +145,6 @@ protected:
const nsString *aAttributes, const nsString *aAttributes,
PRBool &aIsSet) const; PRBool &aIsSet) const;
/** returns PR_TRUE in out-param aIsInline if aNode is inline as defined by HTML DTD */
NS_IMETHOD IsNodeInline(nsIDOMNode *aNode, PRBool &aIsInline) const;
/** returns the closest block parent of aNode, not including aNode itself.
* can return null, for example if aNode is in a document fragment.
* @param aNode The node whose parent we seek.
* @param aBlockParent [OUT] The block parent, if any.
* @return a success value unless an unexpected error occurs.
*/
NS_IMETHOD GetBlockParent(nsIDOMNode *aNode, nsIDOMElement **aBlockParent) const;
NS_IMETHOD GetBlockDelimitedContent(nsIDOMNode *aChild,
nsIDOMNode **aLeftNode,
nsIDOMNode **aRightNode) const;
NS_IMETHOD GetBlockRanges(nsIDOMRange *aRange, nsISupportsArray *aSubRanges) const;
/** returns PR_TRUE in out-param aResult if all nodes between (aStartNode, aStartOffset)
* and (aEndNode, aEndOffset) are inline as defined by HTML DTD.
*/
NS_IMETHOD IntermediateNodesAreInline(nsIDOMRange *aRange,
nsIDOMNode *aStartNode,
PRInt32 aStartOffset,
nsIDOMNode *aEndNode,
PRInt32 aEndOffset,
PRBool &aResult) const;
/** returns the number of things inside aNode in the out-param aCount.
* If aNode is text, returns number of characters.
* If not, returns number of children nodes.
*/
NS_IMETHOD GetLengthOfDOMNode(nsIDOMNode *aNode, PRUint32 &aCount) const;
/** Moves the content between (aNode, aStartOffset) and (aNode, aEndOffset) /** Moves the content between (aNode, aStartOffset) and (aNode, aEndOffset)
* into aNewParentNode, splitting aNode as necessary to maintain the relative * into aNewParentNode, splitting aNode as necessary to maintain the relative
* position of all leaf content. * position of all leaf content.

Просмотреть файл

@ -17,12 +17,12 @@
*/ */
#include "CreateElementTxn.h" #include "CreateElementTxn.h"
#include "nsEditor.h"
#include "nsIDOMDocument.h" #include "nsIDOMDocument.h"
#include "nsIDOMNodeList.h" #include "nsIDOMNodeList.h"
#include "nsIDOMSelection.h" #include "nsIDOMSelection.h"
#include "nsIDOMText.h" #include "nsIDOMText.h"
#include "nsIDOMElement.h" #include "nsIDOMElement.h"
#include "nsIEditorSupport.h"
#ifdef NS_DEBUG #ifdef NS_DEBUG
static PRBool gNoisy = PR_FALSE; static PRBool gNoisy = PR_FALSE;
@ -125,7 +125,7 @@ NS_IMETHODIMP CreateElementTxn::Do(void)
nsresult selectionResult = mEditor->GetSelection(getter_AddRefs(selection)); nsresult selectionResult = mEditor->GetSelection(getter_AddRefs(selection));
if (NS_SUCCEEDED(selectionResult) && selection) { if (NS_SUCCEEDED(selectionResult) && selection) {
PRInt32 offset=0; PRInt32 offset=0;
nsIEditorSupport::GetChildOffset(mNewNode, mParent, offset); nsEditor::GetChildOffset(mNewNode, mParent, offset);
selectionResult = selection->Collapse(mParent, offset); selectionResult = selection->Collapse(mParent, offset);
NS_ASSERTION((NS_SUCCEEDED(selectionResult)), "selection could not be collapsed after undo of insert."); NS_ASSERTION((NS_SUCCEEDED(selectionResult)), "selection could not be collapsed after undo of insert.");
} }
@ -152,7 +152,7 @@ NS_IMETHODIMP CreateElementTxn::Undo(void)
if (NS_SUCCEEDED(selectionResult) && selection) { if (NS_SUCCEEDED(selectionResult) && selection) {
PRInt32 offset=0; PRInt32 offset=0;
if (mRefNode) { if (mRefNode) {
nsIEditorSupport::GetChildOffset(mRefNode, mParent, offset); nsEditor::GetChildOffset(mRefNode, mParent, offset);
} }
selectionResult = selection->Collapse(mParent, offset); selectionResult = selection->Collapse(mParent, offset);
NS_ASSERTION((NS_SUCCEEDED(selectionResult)), "selection could not be collapsed after undo of insert."); NS_ASSERTION((NS_SUCCEEDED(selectionResult)), "selection could not be collapsed after undo of insert.");
@ -183,7 +183,7 @@ NS_IMETHODIMP CreateElementTxn::Redo(void)
result = mEditor->GetSelection(getter_AddRefs(selection)); result = mEditor->GetSelection(getter_AddRefs(selection));
if (NS_SUCCEEDED(result) && selection) { if (NS_SUCCEEDED(result) && selection) {
PRInt32 offset=0; PRInt32 offset=0;
nsIEditorSupport::GetChildOffset(mNewNode, mParent, offset); nsEditor::GetChildOffset(mNewNode, mParent, offset);
nsresult selectionResult = selection->Collapse(mParent, offset); nsresult selectionResult = selection->Collapse(mParent, offset);
NS_ASSERTION((NS_SUCCEEDED(selectionResult)), "selection could not be collapsed after undo of insert."); NS_ASSERTION((NS_SUCCEEDED(selectionResult)), "selection could not be collapsed after undo of insert.");
} }

Просмотреть файл

@ -17,10 +17,10 @@
*/ */
#include "JoinElementTxn.h" #include "JoinElementTxn.h"
#include "nsEditor.h"
#include "nsIDOMNodeList.h" #include "nsIDOMNodeList.h"
#include "nsIDOMCharacterData.h" #include "nsIDOMCharacterData.h"
#include "nsIDOMSelection.h" #include "nsIDOMSelection.h"
#include "nsIEditorSupport.h"
#ifdef NS_DEBUG #ifdef NS_DEBUG
static PRBool gNoisy = PR_FALSE; static PRBool gNoisy = PR_FALSE;
@ -28,9 +28,6 @@ static PRBool gNoisy = PR_FALSE;
static const PRBool gNoisy = PR_FALSE; static const PRBool gNoisy = PR_FALSE;
#endif #endif
static NS_DEFINE_IID(kIEditorSupportIID, NS_IEDITORSUPPORT_IID);
JoinElementTxn::JoinElementTxn() JoinElementTxn::JoinElementTxn()
: EditTxn() : EditTxn()
{ {
@ -84,19 +81,15 @@ NS_IMETHODIMP JoinElementTxn::Do(void)
leftNodeAsText->GetLength(&mOffset); leftNodeAsText->GetLength(&mOffset);
} }
} }
nsCOMPtr<nsIEditorSupport> editor; result = nsEditor::JoinNodesImpl(mRightNode, mLeftNode, mParent, PR_FALSE);
result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); if (NS_SUCCEEDED(result))
if (NS_SUCCEEDED(result) && editor) { {
result = editor->JoinNodesImpl(mRightNode, mLeftNode, mParent, PR_FALSE); if (gNoisy) { printf(" left node = %p removed\n", mLeftNode.get()); }
if (NS_SUCCEEDED(result)) nsCOMPtr<nsIDOMSelection>selection;
mEditor->GetSelection(getter_AddRefs(selection));
if (selection)
{ {
if (gNoisy) { printf(" left node = %p removed\n", mLeftNode.get()); } selection->Collapse(mRightNode, mOffset);
nsCOMPtr<nsIDOMSelection>selection;
mEditor->GetSelection(getter_AddRefs(selection));
if (selection)
{
selection->Collapse(mRightNode, mOffset);
}
} }
} }
} }

Просмотреть файл

@ -17,10 +17,10 @@
*/ */
#include "SplitElementTxn.h" #include "SplitElementTxn.h"
#include "nsEditor.h"
#include "nsIDOMNode.h" #include "nsIDOMNode.h"
#include "nsIDOMSelection.h" #include "nsIDOMSelection.h"
#include "nsIDOMCharacterData.h" #include "nsIDOMCharacterData.h"
#include "nsIEditorSupport.h"
#ifdef NS_DEBUG #ifdef NS_DEBUG
static PRBool gNoisy = PR_FALSE; static PRBool gNoisy = PR_FALSE;
@ -28,7 +28,6 @@ static PRBool gNoisy = PR_FALSE;
static const PRBool gNoisy = PR_FALSE; static const PRBool gNoisy = PR_FALSE;
#endif #endif
static NS_DEFINE_IID(kIEditorSupportIID, NS_IEDITORSUPPORT_IID);
// note that aEditor is not refcounted // note that aEditor is not refcounted
SplitElementTxn::SplitElementTxn() SplitElementTxn::SplitElementTxn()
@ -69,19 +68,14 @@ NS_IMETHODIMP SplitElementTxn::Do(void)
// insert the new node // insert the new node
if ((NS_SUCCEEDED(result)) && (mParent)) if ((NS_SUCCEEDED(result)) && (mParent))
{ {
nsCOMPtr<nsIEditorSupport> editor; result = nsEditor::SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent);
result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); if (NS_SUCCEEDED(result) && mNewLeftNode)
if (NS_SUCCEEDED(result) && editor)
{ {
result = editor->SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent); nsCOMPtr<nsIDOMSelection>selection;
if (NS_SUCCEEDED(result) && mNewLeftNode) mEditor->GetSelection(getter_AddRefs(selection));
if (selection)
{ {
nsCOMPtr<nsIDOMSelection>selection; selection->Collapse(mNewLeftNode, mOffset);
mEditor->GetSelection(getter_AddRefs(selection));
if (selection)
{
selection->Collapse(mNewLeftNode, mOffset);
}
} }
} }
else { else {
@ -105,25 +99,20 @@ NS_IMETHODIMP SplitElementTxn::Undo(void)
// this assumes Do inserted the new node in front of the prior existing node // this assumes Do inserted the new node in front of the prior existing node
nsresult result; nsresult result;
nsCOMPtr<nsIEditorSupport> editor; result = nsEditor::JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent, PR_FALSE);
result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); if (gNoisy)
if (NS_SUCCEEDED(result) && editor) {
printf("** after join left child node %p into right node %p\n", mNewLeftNode.get(), mExistingRightNode.get());
if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
}
if (NS_SUCCEEDED(result))
{ {
result = editor->JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent, PR_FALSE); if (gNoisy) { printf(" left node = %p removed\n", mNewLeftNode.get()); }
if (gNoisy) nsCOMPtr<nsIDOMSelection>selection;
{ mEditor->GetSelection(getter_AddRefs(selection));
printf("** after join left child node %p into right node %p\n", mNewLeftNode.get(), mExistingRightNode.get()); if (selection)
if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
}
if (NS_SUCCEEDED(result))
{ {
if (gNoisy) { printf(" left node = %p removed\n", mNewLeftNode.get()); } selection->Collapse(mExistingRightNode, mOffset);
nsCOMPtr<nsIDOMSelection>selection;
mEditor->GetSelection(getter_AddRefs(selection));
if (selection)
{
selection->Collapse(mExistingRightNode, mOffset);
}
} }
} }
else { else {

Просмотреть файл

@ -19,6 +19,7 @@
#include "nsIDOMDocument.h" #include "nsIDOMDocument.h"
#include "nsEditor.h" #include "nsEditor.h"
#include "nsIEditProperty.h" // to be removed XXX
#include "nsIDOMText.h" #include "nsIDOMText.h"
#include "nsIDOMElement.h" #include "nsIDOMElement.h"
#include "nsIDOMAttr.h" #include "nsIDOMAttr.h"
@ -41,6 +42,7 @@
#include "nsIEnumerator.h" #include "nsIEnumerator.h"
#include "nsIAtom.h" #include "nsIAtom.h"
#include "nsVoidArray.h" #include "nsVoidArray.h"
#include "nsISupportsArray.h"
#include "nsICaret.h" #include "nsICaret.h"
#include "nsIEditActionListener.h" #include "nsIEditActionListener.h"
@ -98,6 +100,7 @@ static NS_DEFINE_IID(kIDOMElementIID, NS_IDOMELEMENT_IID);
static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID);
static NS_DEFINE_IID(kIDOMSelectionIID, NS_IDOMSELECTION_IID); static NS_DEFINE_IID(kIDOMSelectionIID, NS_IDOMSELECTION_IID);
static NS_DEFINE_IID(kIDOMRangeIID, NS_IDOMRANGE_IID); static NS_DEFINE_IID(kIDOMRangeIID, NS_IDOMRANGE_IID);
static NS_DEFINE_CID(kCRangeCID, NS_RANGE_CID);
static NS_DEFINE_IID(kIDOMDocumentIID, NS_IDOMDOCUMENT_IID); static NS_DEFINE_IID(kIDOMDocumentIID, NS_IDOMDOCUMENT_IID);
static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID); static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID);
static NS_DEFINE_IID(kIPresShellIID, NS_IPRESSHELL_IID); static NS_DEFINE_IID(kIPresShellIID, NS_IPRESSHELL_IID);
@ -106,7 +109,6 @@ static NS_DEFINE_IID(kIEditFactoryIID, NS_IEDITORFACTORY_IID);
static NS_DEFINE_IID(kITextEditFactoryIID, NS_ITEXTEDITORFACTORY_IID); static NS_DEFINE_IID(kITextEditFactoryIID, NS_ITEXTEDITORFACTORY_IID);
static NS_DEFINE_IID(kIHTMLEditFactoryIID, NS_IHTMLEDITORFACTORY_IID); static NS_DEFINE_IID(kIHTMLEditFactoryIID, NS_IHTMLEDITORFACTORY_IID);
static NS_DEFINE_IID(kIEditorIID, NS_IEDITOR_IID); static NS_DEFINE_IID(kIEditorIID, NS_IEDITOR_IID);
static NS_DEFINE_IID(kIEditorSupportIID, NS_IEDITORSUPPORT_IID);
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kEditorCID, NS_EDITOR_CID); static NS_DEFINE_IID(kEditorCID, NS_EDITOR_CID);
static NS_DEFINE_CID(kTextEditorCID, NS_TEXTEDITOR_CID); static NS_DEFINE_CID(kTextEditorCID, NS_TEXTEDITOR_CID);
@ -144,8 +146,11 @@ static NS_DEFINE_CID(kCDOMRangeCID, NS_RANGE_CID);
#define NS_ERROR_EDITOR_NO_SELECTION NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_EDITOR,1) #define NS_ERROR_EDITOR_NO_SELECTION NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_EDITOR,1)
#define NS_ERROR_EDITOR_NO_TEXTNODE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_EDITOR,2) #define NS_ERROR_EDITOR_NO_TEXTNODE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_EDITOR,2)
const char* nsEditor::kMOZEditorBogusNodeAttr="MOZ_EDITOR_BOGUS_NODE";
const char* nsEditor::kMOZEditorBogusNodeValue="TRUE";
#ifdef NS_DEBUG_EDITOR #ifdef NS_DEBUG_EDITOR
static PRBool gNoisy = PR_FALSE; static PRBool gNoisy = PR_TRUE;
#else #else
static const PRBool gNoisy = PR_FALSE; static const PRBool gNoisy = PR_FALSE;
#endif #endif
@ -324,7 +329,7 @@ nsEditor::~nsEditor()
//BEGIN nsIEditor interface implementations // BEGIN nsEditor core implementation
NS_IMPL_ADDREF(nsEditor) NS_IMPL_ADDREF(nsEditor)
@ -351,11 +356,6 @@ nsEditor::QueryInterface(REFNSIID aIID, void** aInstancePtr)
NS_ADDREF_THIS(); NS_ADDREF_THIS();
return NS_OK; return NS_OK;
} }
if (aIID.Equals(kIEditorSupportIID)) {
*aInstancePtr = (void*)(nsIEditorSupport*)this;
NS_ADDREF_THIS();
return NS_OK;
}
return NS_NOINTERFACE; return NS_NOINTERFACE;
} }
@ -665,109 +665,6 @@ nsEditor::InsertBreak()
//BEGIN nsEditor Private methods //BEGIN nsEditor Private methods
NS_IMETHODIMP
nsEditor::GetFirstNodeOfType(nsIDOMNode *aStartNode, const nsString &aTag, nsIDOMNode **aResult)
{
nsresult result=NS_OK;
if (!mDoc)
return NS_ERROR_NULL_POINTER;
if (!aResult)
return NS_ERROR_NULL_POINTER;
/* If no node set, get root node */
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIDOMElement> element;
if (nsnull==aStartNode)
{
mDoc->GetDocumentElement(getter_AddRefs(element));
result = element->QueryInterface(kIDOMNodeIID,getter_AddRefs(node));
if (NS_FAILED(result))
return result;
if (!node)
return NS_ERROR_NULL_POINTER;
}
else
node = do_QueryInterface(aStartNode);
*aResult = nsnull;
nsCOMPtr<nsIDOMNode> childNode;
result = node->GetFirstChild(getter_AddRefs(childNode));
while (childNode)
{
result = childNode->QueryInterface(kIDOMNodeIID,getter_AddRefs(element));
nsAutoString tag;
if (NS_SUCCEEDED(result) && (element))
{
element->GetTagName(tag);
if (PR_TRUE==aTag.Equals(tag))
{
return (childNode->QueryInterface(kIDOMNodeIID,(void **) aResult)); // does the addref
}
else
{
nsresult result = GetFirstNodeOfType(childNode, aTag, aResult);
if (nsnull!=*aResult)
return result;
}
}
nsCOMPtr<nsIDOMNode> temp = childNode;
temp->GetNextSibling(getter_AddRefs(childNode));
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsEditor::GetFirstTextNode(nsIDOMNode *aNode, nsIDOMNode **aRetNode)
{
if (!aNode || !aRetNode)
{
NS_NOTREACHED("GetFirstTextNode Failed");
return NS_ERROR_NULL_POINTER;
}
PRUint16 mType;
PRBool mCNodes;
nsCOMPtr<nsIDOMNode> answer;
aNode->GetNodeType(&mType);
if (nsIDOMNode::ELEMENT_NODE == mType) {
if (NS_SUCCEEDED(aNode->HasChildNodes(&mCNodes)) && PR_TRUE == mCNodes)
{
nsCOMPtr<nsIDOMNode> node1;
nsCOMPtr<nsIDOMNode> node2;
if (!NS_SUCCEEDED(aNode->GetFirstChild(getter_AddRefs(node1))))
{
NS_NOTREACHED("GetFirstTextNode Failed");
}
while(!answer && node1)
{
GetFirstTextNode(node1, getter_AddRefs(answer));
node1->GetNextSibling(getter_AddRefs(node2));
node1 = node2;
}
}
}
else if (nsIDOMNode::TEXT_NODE == mType) {
answer = do_QueryInterface(aNode);
}
// OK, now return the answer, if any
*aRetNode = answer;
if (*aRetNode)
NS_IF_ADDREF(*aRetNode);
else
return NS_ERROR_FAILURE;
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
nsEditor::Do(nsITransaction *aTxn) nsEditor::Do(nsITransaction *aTxn)
@ -1510,7 +1407,7 @@ NS_IMETHODIMP nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNod
selectedNode = do_QueryInterface(parentSelectedNode); selectedNode = do_QueryInterface(parentSelectedNode);
selectedNode->GetParentNode(getter_AddRefs(parentSelectedNode)); selectedNode->GetParentNode(getter_AddRefs(parentSelectedNode));
selectedParentNodeAsText->GetLength(&selectedNodeContentCount); selectedParentNodeAsText->GetLength(&selectedNodeContentCount);
nsIEditorSupport::GetChildOffset(selectedNode, parentSelectedNode, indexOfTextNodeInParent); GetChildOffset(selectedNode, parentSelectedNode, indexOfTextNodeInParent);
if ((offsetOfSelectedNode!=0) && (((PRUint32)offsetOfSelectedNode)!=selectedNodeContentCount)) if ((offsetOfSelectedNode!=0) && (((PRUint32)offsetOfSelectedNode)!=selectedNodeContentCount))
{ {
@ -1518,7 +1415,7 @@ NS_IMETHODIMP nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNod
result = SplitNode(selectedNode, offsetOfSelectedNode, getter_AddRefs(newSiblingNode)); result = SplitNode(selectedNode, offsetOfSelectedNode, getter_AddRefs(newSiblingNode));
// now get the node's offset in it's parent, and insert the new tag there // now get the node's offset in it's parent, and insert the new tag there
if (NS_SUCCEEDED(result)) { if (NS_SUCCEEDED(result)) {
result = nsIEditorSupport::GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode); result = GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
} }
} }
else else
@ -1527,7 +1424,7 @@ NS_IMETHODIMP nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNod
offsetOfNewNode = indexOfTextNodeInParent; // insert new node as previous sibling to selection parent offsetOfNewNode = indexOfTextNodeInParent; // insert new node as previous sibling to selection parent
} }
else { // insert new node as last child else { // insert new node as last child
nsIEditorSupport::GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode); GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
offsetOfNewNode++; // offsets are 0-based, and we need the index of the new node offsetOfNewNode++; // offsets are 0-based, and we need the index of the new node
} }
} }
@ -1560,7 +1457,7 @@ NS_IMETHODIMP nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNod
result = SplitNode(selectedNode, offsetOfSelectedNode, getter_AddRefs(newSiblingNode)); result = SplitNode(selectedNode, offsetOfSelectedNode, getter_AddRefs(newSiblingNode));
// now get the node's offset in it's parent, and insert the new tag there // now get the node's offset in it's parent, and insert the new tag there
if (NS_SUCCEEDED(result)) { if (NS_SUCCEEDED(result)) {
result = nsIEditorSupport::GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode); result = GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
} }
} }
else else
@ -1569,7 +1466,7 @@ NS_IMETHODIMP nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNod
offsetOfNewNode = 0; // insert new node as first child offsetOfNewNode = 0; // insert new node as first child
} }
else { // insert new node as last child else { // insert new node as last child
nsIEditorSupport::GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode); GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
offsetOfNewNode++; // offsets are 0-based, and we need the index of the new node offsetOfNewNode++; // offsets are 0-based, and we need the index of the new node
} }
} }
@ -1821,108 +1718,6 @@ nsEditor::CreateTxnForDeleteInsertionPoint(nsIDOMRange *aRange,
return result; return result;
} }
NS_IMETHODIMP
nsEditor::GetPriorNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode)
{
nsresult result;
*aResultNode = nsnull;
// if aCurrentNode has a left sibling, return that sibling's rightmost child (or itself if it has no children)
result = aCurrentNode->GetPreviousSibling(aResultNode);
if ((NS_SUCCEEDED(result)) && *aResultNode)
return GetRightmostChild(*aResultNode, aResultNode);
// otherwise, walk up the parent change until there is a child that comes before
// the ancestor of aCurrentNode. Then return that node's rightmost child
nsCOMPtr<nsIDOMNode> parent(do_QueryInterface(aCurrentNode));
do {
nsCOMPtr<nsIDOMNode> node(parent);
result = node->GetParentNode(getter_AddRefs(parent));
if ((NS_SUCCEEDED(result)) && parent)
{
result = parent->GetPreviousSibling(getter_AddRefs(node));
if ((NS_SUCCEEDED(result)) && node)
{
return GetRightmostChild(node, aResultNode);
}
}
} while ((NS_SUCCEEDED(result)) && parent);
return result;
}
NS_IMETHODIMP
nsEditor::GetNextNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode)
{
nsresult result;
*aResultNode = nsnull;
// if aCurrentNode has a right sibling, return that sibling's leftmost child (or itself if it has no children)
result = aCurrentNode->GetNextSibling(aResultNode);
if ((NS_SUCCEEDED(result)) && *aResultNode)
return GetLeftmostChild(*aResultNode, aResultNode);
// otherwise, walk up the parent change until there is a child that comes before
// the ancestor of aCurrentNode. Then return that node's rightmost child
nsCOMPtr<nsIDOMNode> parent(do_QueryInterface(aCurrentNode));
do {
nsCOMPtr<nsIDOMNode> node(parent);
result = node->GetParentNode(getter_AddRefs(parent));
if ((NS_SUCCEEDED(result)) && parent)
{
result = parent->GetNextSibling(getter_AddRefs(node));
if ((NS_SUCCEEDED(result)) && node)
{
return GetLeftmostChild(node, aResultNode);
}
}
} while ((NS_SUCCEEDED(result)) && parent);
return result;
}
NS_IMETHODIMP
nsEditor::GetRightmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode)
{
nsresult result = NS_OK;
nsCOMPtr<nsIDOMNode> resultNode(do_QueryInterface(aCurrentNode));
PRBool hasChildren;
resultNode->HasChildNodes(&hasChildren);
while ((NS_SUCCEEDED(result)) && (PR_TRUE==hasChildren))
{
nsCOMPtr<nsIDOMNode> temp(resultNode);
temp->GetLastChild(getter_AddRefs(resultNode));
resultNode->HasChildNodes(&hasChildren);
}
if (NS_SUCCEEDED(result)) {
*aResultNode = resultNode;
NS_ADDREF(*aResultNode);
}
return result;
}
NS_IMETHODIMP
nsEditor::GetLeftmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode)
{
nsresult result = NS_OK;
nsCOMPtr<nsIDOMNode> resultNode(do_QueryInterface(aCurrentNode));
PRBool hasChildren;
resultNode->HasChildNodes(&hasChildren);
while ((NS_SUCCEEDED(result)) && (PR_TRUE==hasChildren))
{
nsCOMPtr<nsIDOMNode> temp(resultNode);
temp->GetFirstChild(getter_AddRefs(resultNode));
resultNode->HasChildNodes(&hasChildren);
}
if (NS_SUCCEEDED(result)) {
*aResultNode = resultNode;
NS_ADDREF(*aResultNode);
}
return result;
}
NS_IMETHODIMP NS_IMETHODIMP
nsEditor::SplitNode(nsIDOMNode * aNode, nsEditor::SplitNode(nsIDOMNode * aNode,
@ -2037,7 +1832,12 @@ NS_IMETHODIMP nsEditor::CreateTxnForJoinNode(nsIDOMNode *aLeftNode,
return result; return result;
} }
NS_IMETHODIMP
// END nsEditor core implementation
// BEGIN nsEditor public static helper methods
nsresult
nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode, nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode,
PRInt32 aOffset, PRInt32 aOffset,
nsIDOMNode* aNewLeftNode, nsIDOMNode* aNewLeftNode,
@ -2113,7 +1913,7 @@ nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode,
return result; return result;
} }
NS_IMETHODIMP nsresult
nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep, nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep,
nsIDOMNode * aNodeToJoin, nsIDOMNode * aNodeToJoin,
nsIDOMNode * aParent, nsIDOMNode * aParent,
@ -2203,7 +2003,8 @@ nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep,
return result; return result;
} }
nsresult nsIEditorSupport::GetChildOffset(nsIDOMNode *aChild, nsIDOMNode *aParent, PRInt32 &aOffset) nsresult
nsEditor::GetChildOffset(nsIDOMNode *aChild, nsIDOMNode *aParent, PRInt32 &aOffset)
{ {
NS_ASSERTION((aChild && aParent), "bad args"); NS_ASSERTION((aChild && aParent), "bad args");
nsresult result = NS_ERROR_NULL_POINTER; nsresult result = NS_ERROR_NULL_POINTER;
@ -2236,8 +2037,478 @@ nsresult nsIEditorSupport::GetChildOffset(nsIDOMNode *aChild, nsIDOMNode *aParen
return result; return result;
} }
// returns the number of things inside aNode.
// If aNode is text, returns number of characters. If not, returns number of children nodes.
nsresult
nsEditor::GetLengthOfDOMNode(nsIDOMNode *aNode, PRUint32 &aCount)
{
aCount = 0;
if (!aNode) { return NS_ERROR_NULL_POINTER; }
nsresult result=NS_OK;
nsCOMPtr<nsIDOMCharacterData>nodeAsChar;
nodeAsChar = do_QueryInterface(aNode);
if (nodeAsChar) {
nodeAsChar->GetLength(&aCount);
}
else
{
PRBool hasChildNodes;
aNode->HasChildNodes(&hasChildNodes);
if (PR_TRUE==hasChildNodes)
{
nsCOMPtr<nsIDOMNodeList>nodeList;
result = aNode->GetChildNodes(getter_AddRefs(nodeList));
if (NS_SUCCEEDED(result) && nodeList) {
nodeList->GetLength(&aCount);
}
}
}
return result;
}
// content-based inline vs. block query
nsresult
nsEditor::IsNodeInline(nsIDOMNode *aNode, PRBool &aIsInline)
{
// this is a content-based implementation
if (!aNode) { return NS_ERROR_NULL_POINTER; }
nsresult result;
aIsInline = PR_FALSE;
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(aNode);
if (element)
{
nsAutoString tag;
result = element->GetTagName(tag);
if (NS_SUCCEEDED(result))
{
nsIAtom *tagAtom = NS_NewAtom(tag);
if (!tagAtom) { return NS_ERROR_NULL_POINTER; }
if (tagAtom==nsIEditProperty::a ||
tagAtom==nsIEditProperty::b ||
tagAtom==nsIEditProperty::big ||
tagAtom==nsIEditProperty::font ||
tagAtom==nsIEditProperty::i ||
tagAtom==nsIEditProperty::span ||
tagAtom==nsIEditProperty::small ||
tagAtom==nsIEditProperty::strike ||
tagAtom==nsIEditProperty::sub ||
tagAtom==nsIEditProperty::sup ||
tagAtom==nsIEditProperty::tt ||
tagAtom==nsIEditProperty::u )
{
aIsInline = PR_TRUE;
}
}
}
return NS_OK;
}
nsresult
nsEditor::GetBlockParent(nsIDOMNode *aNode, nsIDOMElement **aBlockParent)
{
nsresult result = NS_OK;
if (!aBlockParent) {return NS_ERROR_NULL_POINTER;}
*aBlockParent = nsnull;
nsCOMPtr<nsIDOMNode>parent;
nsCOMPtr<nsIDOMNode>temp;
result = aNode->GetParentNode(getter_AddRefs(parent));
while (NS_SUCCEEDED(result) && parent)
{
PRBool isInline;
result = IsNodeInline(parent, isInline);
if (PR_FALSE==isInline)
{
parent->QueryInterface(nsIDOMElement::GetIID(), (void**)aBlockParent);
break;
}
result = parent->GetParentNode(getter_AddRefs(temp));
parent = do_QueryInterface(temp);
}
if (gNoisy) { printf("GetBlockParent for %p returning parent %p\n", aNode, *aBlockParent); }
return result;
}
nsresult
nsEditor::GetBlockSection(nsIDOMNode *aChild,
nsIDOMNode **aLeftNode,
nsIDOMNode **aRightNode)
{
nsresult result = NS_OK;
if (!aChild || !aLeftNode || !aRightNode) {return NS_ERROR_NULL_POINTER;}
*aLeftNode = aChild;
*aRightNode = aChild;
nsCOMPtr<nsIDOMNode>sibling;
result = aChild->GetPreviousSibling(getter_AddRefs(sibling));
while ((NS_SUCCEEDED(result)) && sibling)
{
PRBool isInline;
IsNodeInline(sibling, isInline);
if (PR_FALSE==isInline)
{
nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
if (!nodeAsText) {
break;
}
// XXX: needs some logic to work for other leaf nodes besides text!
}
*aLeftNode = sibling;
result = (*aLeftNode)->GetPreviousSibling(getter_AddRefs(sibling));
}
NS_ADDREF((*aLeftNode));
// now do the right side
result = aChild->GetNextSibling(getter_AddRefs(sibling));
while ((NS_SUCCEEDED(result)) && sibling)
{
PRBool isInline;
IsNodeInline(sibling, isInline);
if (PR_FALSE==isInline)
{
nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
if (!nodeAsText) {
break;
}
}
*aRightNode = sibling;
result = (*aRightNode)->GetNextSibling(getter_AddRefs(sibling));
}
NS_ADDREF((*aRightNode));
if (gNoisy) { printf("GetBlockSection returning %p %p\n",
(*aLeftNode), (*aRightNode)); }
return result;
}
nsresult
nsEditor::GetBlockSectionsForRange(nsIDOMRange *aRange, nsISupportsArray *aSections)
{
if (!aRange || !aSections) {return NS_ERROR_NULL_POINTER;}
nsresult result;
nsCOMPtr<nsIContentIterator>iter;
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
kIContentIteratorIID, getter_AddRefs(iter));
if ((NS_SUCCEEDED(result)) && iter)
{
nsCOMPtr<nsIDOMRange> lastRange;
iter->Init(aRange);
nsCOMPtr<nsIContent> currentContent;
iter->CurrentNode(getter_AddRefs(currentContent));
while (NS_COMFALSE == iter->IsDone())
{
nsCOMPtr<nsIDOMNode>currentNode = do_QueryInterface(currentContent);
if (currentNode)
{
nsCOMPtr<nsIAtom> currentContentTag;
currentContent->GetTag(*getter_AddRefs(currentContentTag));
// <BR> divides block content ranges. We can achieve this by nulling out lastRange
if (nsIEditProperty::br==currentContentTag)
{
lastRange = do_QueryInterface(nsnull);
}
else
{
PRBool isInlineOrText;
result = IsNodeInline(currentNode, isInlineOrText);
if (PR_FALSE==isInlineOrText)
{
PRUint16 nodeType;
currentNode->GetNodeType(&nodeType);
if (nsIDOMNode::TEXT_NODE == nodeType) {
isInlineOrText = PR_TRUE;
}
}
if (PR_TRUE==isInlineOrText)
{
nsCOMPtr<nsIDOMNode>leftNode;
nsCOMPtr<nsIDOMNode>rightNode;
result = GetBlockSection(currentNode,
getter_AddRefs(leftNode),
getter_AddRefs(rightNode));
if (gNoisy) {printf("currentNode %p has block content (%p,%p)\n", currentNode.get(), leftNode.get(), rightNode.get());}
if ((NS_SUCCEEDED(result)) && leftNode && rightNode)
{
// add range to the list if it doesn't overlap with the previous range
PRBool addRange=PR_TRUE;
if (lastRange)
{
nsCOMPtr<nsIDOMNode> lastStartNode;
nsCOMPtr<nsIDOMElement> blockParentOfLastStartNode;
lastRange->GetStartParent(getter_AddRefs(lastStartNode));
result = GetBlockParent(lastStartNode, getter_AddRefs(blockParentOfLastStartNode));
if ((NS_SUCCEEDED(result)) && blockParentOfLastStartNode)
{
if (gNoisy) {printf("lastStartNode %p has block parent %p\n", lastStartNode.get(), blockParentOfLastStartNode.get());}
nsCOMPtr<nsIDOMElement> blockParentOfLeftNode;
result = GetBlockParent(leftNode, getter_AddRefs(blockParentOfLeftNode));
if ((NS_SUCCEEDED(result)) && blockParentOfLeftNode)
{
if (gNoisy) {printf("leftNode %p has block parent %p\n", leftNode.get(), blockParentOfLeftNode.get());}
if (blockParentOfLastStartNode==blockParentOfLeftNode) {
addRange = PR_FALSE;
}
}
}
}
if (PR_TRUE==addRange)
{
if (gNoisy) {printf("adding range, setting lastRange with start node %p\n", leftNode.get());}
nsCOMPtr<nsIDOMRange> range;
result = nsComponentManager::CreateInstance(kCRangeCID, nsnull,
kIDOMRangeIID, getter_AddRefs(range));
if ((NS_SUCCEEDED(result)) && range)
{ // initialize the range
range->SetStart(leftNode, 0);
range->SetEnd(rightNode, 0);
aSections->AppendElement(range);
lastRange = do_QueryInterface(range);
}
}
}
}
}
}
/* do not check result here, and especially do not return the result code.
* we rely on iter->IsDone to tell us when the iteration is complete
*/
iter->Next();
iter->CurrentNode(getter_AddRefs(currentContent));
}
}
return result;
}
nsresult
nsEditor::IntermediateNodesAreInline(nsIDOMRange *aRange,
nsIDOMNode *aStartNode,
PRInt32 aStartOffset,
nsIDOMNode *aEndNode,
PRInt32 aEndOffset,
PRBool &aResult)
{
aResult = PR_TRUE; // init out param. we assume the condition is true unless we find a node that violates it
if (!aStartNode || !aEndNode || !aRange) { return NS_ERROR_NULL_POINTER; }
nsCOMPtr<nsIContentIterator>iter;
nsresult result;
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
kIContentIteratorIID, getter_AddRefs(iter));
//XXX: maybe CreateInstance is expensive, and I should keep around a static iter?
// as long as this method can't be called recursively or re-entrantly!
if ((NS_SUCCEEDED(result)) && iter)
{
nsCOMPtr<nsIContent>startContent;
startContent = do_QueryInterface(aStartNode);
nsCOMPtr<nsIContent>endContent;
endContent = do_QueryInterface(aEndNode);
if (startContent && endContent)
{
iter->Init(aRange);
nsCOMPtr<nsIContent> content;
iter->CurrentNode(getter_AddRefs(content));
while (NS_COMFALSE == iter->IsDone())
{
if ((content.get() != startContent.get()) &&
(content.get() != endContent.get()))
{
nsCOMPtr<nsIDOMNode>currentNode;
currentNode = do_QueryInterface(content);
PRBool isInline=PR_FALSE;
IsNodeInline(currentNode, isInline);
if (PR_FALSE==isInline)
{
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
nodeAsText = do_QueryInterface(currentNode);
if (!nodeAsText) // text nodes don't count in this check, so ignore them
{
aResult = PR_FALSE;
break;
}
}
}
/* do not check result here, and especially do not return the result code.
* we rely on iter->IsDone to tell us when the iteration is complete
*/
iter->Next();
iter->CurrentNode(getter_AddRefs(content));
}
}
}
return result;
}
nsresult
nsEditor::GetPriorNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode)
{
nsresult result;
*aResultNode = nsnull;
// if aCurrentNode has a left sibling, return that sibling's rightmost child (or itself if it has no children)
result = aCurrentNode->GetPreviousSibling(aResultNode);
if ((NS_SUCCEEDED(result)) && *aResultNode)
return GetRightmostChild(*aResultNode, aResultNode);
// otherwise, walk up the parent change until there is a child that comes before
// the ancestor of aCurrentNode. Then return that node's rightmost child
nsCOMPtr<nsIDOMNode> parent(do_QueryInterface(aCurrentNode));
do {
nsCOMPtr<nsIDOMNode> node(parent);
result = node->GetParentNode(getter_AddRefs(parent));
if ((NS_SUCCEEDED(result)) && parent)
{
result = parent->GetPreviousSibling(getter_AddRefs(node));
if ((NS_SUCCEEDED(result)) && node)
{
return GetRightmostChild(node, aResultNode);
}
}
} while ((NS_SUCCEEDED(result)) && parent);
return result;
}
nsresult
nsEditor::GetNextNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode)
{
nsresult result;
*aResultNode = nsnull;
// if aCurrentNode has a right sibling, return that sibling's leftmost child (or itself if it has no children)
result = aCurrentNode->GetNextSibling(aResultNode);
if ((NS_SUCCEEDED(result)) && *aResultNode)
return GetLeftmostChild(*aResultNode, aResultNode);
// otherwise, walk up the parent change until there is a child that comes before
// the ancestor of aCurrentNode. Then return that node's rightmost child
nsCOMPtr<nsIDOMNode> parent(do_QueryInterface(aCurrentNode));
do {
nsCOMPtr<nsIDOMNode> node(parent);
result = node->GetParentNode(getter_AddRefs(parent));
if ((NS_SUCCEEDED(result)) && parent)
{
result = parent->GetNextSibling(getter_AddRefs(node));
if ((NS_SUCCEEDED(result)) && node)
{
return GetLeftmostChild(node, aResultNode);
}
}
} while ((NS_SUCCEEDED(result)) && parent);
return result;
}
nsresult
nsEditor::GetRightmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode)
{
nsresult result = NS_OK;
nsCOMPtr<nsIDOMNode> resultNode(do_QueryInterface(aCurrentNode));
PRBool hasChildren;
resultNode->HasChildNodes(&hasChildren);
while ((NS_SUCCEEDED(result)) && (PR_TRUE==hasChildren))
{
nsCOMPtr<nsIDOMNode> temp(resultNode);
temp->GetLastChild(getter_AddRefs(resultNode));
resultNode->HasChildNodes(&hasChildren);
}
if (NS_SUCCEEDED(result)) {
*aResultNode = resultNode;
NS_ADDREF(*aResultNode);
}
return result;
}
nsresult
nsEditor::GetLeftmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode)
{
nsresult result = NS_OK;
nsCOMPtr<nsIDOMNode> resultNode(do_QueryInterface(aCurrentNode));
PRBool hasChildren;
resultNode->HasChildNodes(&hasChildren);
while ((NS_SUCCEEDED(result)) && (PR_TRUE==hasChildren))
{
nsCOMPtr<nsIDOMNode> temp(resultNode);
temp->GetFirstChild(getter_AddRefs(resultNode));
resultNode->HasChildNodes(&hasChildren);
}
if (NS_SUCCEEDED(result)) {
*aResultNode = resultNode;
NS_ADDREF(*aResultNode);
}
return result;
}
PRBool
nsEditor::NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag)
{
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(aNode);
if (element)
{
nsAutoString tag;
element->GetTagName(tag);
if (tag.Equals(aTag->GetUnicode()))
{
return PR_TRUE;
}
}
return PR_FALSE;
}
PRBool
nsEditor::IsEditable(nsIDOMNode *aNode)
{
if (!aNode) return PR_FALSE;
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(aNode);
if (element)
{
nsAutoString att(kMOZEditorBogusNodeAttr);
nsAutoString val;
(void)element->GetAttribute(att, val);
if (val.Equals(kMOZEditorBogusNodeValue)) {
return PR_FALSE;
}
else {
return PR_TRUE;
}
}
else
{
nsCOMPtr<nsIDOMCharacterData>text;
text = do_QueryInterface(aNode);
if (text)
{
nsAutoString data;
text->GetData(data);
PRUint32 length = data.Length();
if (0==length) {
return PR_FALSE;
}
// if the node contains only newlines, it's not editable
PRUint32 i;
for (i=0; i<length; i++)
{
if ('\n'!=data.CharAt(0)) {
return PR_TRUE;
}
}
return PR_FALSE;
}
}
return PR_TRUE;
}
//END nsEditor static utility methods
//END nsEditor Private methods
void nsEditor::HACKForceRedraw() void nsEditor::HACKForceRedraw()
{ {
@ -2398,42 +2669,96 @@ nsEditor::DebugDumpContent() const
return NS_OK; return NS_OK;
} }
//END nsEditor Private methods nsresult
nsEditor::GetFirstNodeOfType(nsIDOMNode *aStartNode,
/* ----- TEST METHODS ----- */ const nsString &aTag,
// Methods defined here are TEMPORARY nsIDOMNode **aResult)
/* ORIGINAL version by Steve - KEEP FOR REFERENCE
NS_IMETHODIMP GetColIndexForCell(nsIPresShell *aPresShell, nsIDOMNode *aCellNode, PRInt32 &aCellIndex)
{ {
aCellIndex=0; // initialize out param nsresult result=NS_OK;
nsresult result = NS_ERROR_FAILURE; // we return an error unless we get the index
if ((nsnull!=aCellNode) && (nsnull!=aPresShell)) if (!aStartNode)
{ // get the content interface return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIContent> nodeAsContent(aCellNode); if (!aResult)
if (nodeAsContent) return NS_ERROR_NULL_POINTER;
{ // get the frame from the content interface
nsISupports *layoutObject=nsnull; // frames are not ref counted, so don't use an nsCOMPtr nsCOMPtr<nsIDOMElement> element;
result = aPresShell->GetLayoutObjectFor(nodeAsContent, &layoutObject); *aResult = nsnull;
if ((NS_SUCCEEDED(result)) && (nsnull!=layoutObject)) nsCOMPtr<nsIDOMNode> childNode;
{ // get the table cell interface from the frame result = aStartNode->GetFirstChild(getter_AddRefs(childNode));
nsITableCellLayout *cellLayoutObject=nsnull; // again, frames are not ref-counted while (childNode)
result = layoutObject->QueryInterface(nsITableCellLayout::GetIID(), (void**)(&cellLayoutObject)); {
if ((NS_SUCCEEDED(result)) && (nsnull!=cellLayoutObject)) result = childNode->QueryInterface(kIDOMNodeIID,getter_AddRefs(element));
{ // get the index nsAutoString tag;
result = cellLayoutObject->GetColIndex(aCellIndex); if (NS_SUCCEEDED(result) && (element))
} {
element->GetTagName(tag);
if (PR_TRUE==aTag.Equals(tag))
{
return (childNode->QueryInterface(kIDOMNodeIID,(void **) aResult)); // does the addref
}
else
{
nsresult result = GetFirstNodeOfType(childNode, aTag, aResult);
if (nsnull!=*aResult)
return result;
}
}
nsCOMPtr<nsIDOMNode> temp = childNode;
temp->GetNextSibling(getter_AddRefs(childNode));
}
return NS_ERROR_FAILURE;
}
nsresult
nsEditor::GetFirstTextNode(nsIDOMNode *aNode, nsIDOMNode **aRetNode)
{
if (!aNode || !aRetNode)
{
NS_NOTREACHED("GetFirstTextNode Failed");
return NS_ERROR_NULL_POINTER;
}
PRUint16 mType;
PRBool mCNodes;
nsCOMPtr<nsIDOMNode> answer;
aNode->GetNodeType(&mType);
if (nsIDOMNode::ELEMENT_NODE == mType) {
if (NS_SUCCEEDED(aNode->HasChildNodes(&mCNodes)) && PR_TRUE == mCNodes)
{
nsCOMPtr<nsIDOMNode> node1;
nsCOMPtr<nsIDOMNode> node2;
if (!NS_SUCCEEDED(aNode->GetFirstChild(getter_AddRefs(node1))))
{
NS_NOTREACHED("GetFirstTextNode Failed");
}
while(!answer && node1)
{
GetFirstTextNode(node1, getter_AddRefs(answer));
node1->GetNextSibling(getter_AddRefs(node2));
node1 = node2;
} }
} }
} }
else { else if (nsIDOMNode::TEXT_NODE == mType) {
result = NS_ERROR_NULL_POINTER; answer = do_QueryInterface(aNode);
} }
return result;
}
*/
/* ----- END TEST METHODS ----- */ // OK, now return the answer, if any
*aRetNode = answer;
if (*aRetNode)
NS_IF_ADDREF(*aRetNode);
else
return NS_ERROR_FAILURE;
return NS_OK;
}
//END nsEditor Private methods
NS_IMETHODIMP nsEditor::DoInitialPreeeditInsert(const nsString& aStringToInsert) NS_IMETHODIMP nsEditor::DoInitialPreeeditInsert(const nsString& aStringToInsert)
{ {
@ -2601,3 +2926,4 @@ nsEditor::SetPreeditText(const nsString& aStringToInsert)
EndTransaction(); EndTransaction();
return result; return result;
} }

Просмотреть файл

@ -21,7 +21,6 @@
#include "prmon.h" #include "prmon.h"
#include "nsIEditor.h" #include "nsIEditor.h"
#include "nsIEditorSupport.h"
#include "nsIContextLoader.h" #include "nsIContextLoader.h"
#include "nsIDOMDocument.h" #include "nsIDOMDocument.h"
#include "nsIDOMEventListener.h" #include "nsIDOMEventListener.h"
@ -46,6 +45,7 @@ class SplitElementTxn;
class JoinElementTxn; class JoinElementTxn;
class EditAggregateTxn; class EditAggregateTxn;
class nsVoidArray; class nsVoidArray;
class nsISupportsArray;
//This is the monitor for the editor. //This is the monitor for the editor.
PRMonitor *getEditorMonitor(); PRMonitor *getEditorMonitor();
@ -56,7 +56,7 @@ PRMonitor *getEditorMonitor();
* manager, event interfaces. the idea for the event interfaces is to have them * manager, event interfaces. the idea for the event interfaces is to have them
* delegate the actual commands to the editor independent of the XPFE implementation. * delegate the actual commands to the editor independent of the XPFE implementation.
*/ */
class nsEditor : public nsIEditor, public nsIEditorSupport class nsEditor : public nsIEditor
{ {
private: private:
nsIPresShell *mPresShell; nsIPresShell *mPresShell;
@ -75,6 +75,10 @@ protected:
nsIDOMDocument * mDoc; nsIDOMDocument * mDoc;
public: public:
const static char* nsEditor::kMOZEditorBogusNodeAttr;
const static char* nsEditor::kMOZEditorBogusNodeValue;
/** The default constructor. This should suffice. the setting of the interfaces is done /** The default constructor. This should suffice. the setting of the interfaces is done
* after the construction of the editor class. * after the construction of the editor class.
*/ */
@ -186,32 +190,6 @@ public:
/*END nsIEditor interfaces*/ /*END nsIEditor interfaces*/
/*BEGIN public methods unique to nsEditor. These will get moved to an interface
if they survive.
*/
/** GetFirstTextNode ADDREFFS and will get the next available text node from the passed
* in node parameter it can also return NS_ERROR_FAILURE if no text nodes are available
* now it simply returns the first node in the dom
* @param nsIDOMNode *aNode is the node to start looking from
* @param nsIDOMNode **aRetNode is the return location of the text dom node
*
* NOTE: this method will probably be removed.
*/
NS_IMETHOD GetFirstTextNode(nsIDOMNode *aNode, nsIDOMNode **aRetNode);
/** GetFirstNodeOfType ADDREFFS and will get the next available node from the passed
* in aStartNode parameter of type aTag.
* It can also return NS_ERROR_FAILURE if no such nodes are available
* @param nsIDOMNode *aStartNode is the node to start looking from
* @param nsIAtom *aTag is the type of node we are searching for
* @param nsIDOMNode **aResult is the node we found, or nsnull if there is none
*/
NS_IMETHOD GetFirstNodeOfType(nsIDOMNode *aStartNode, const nsString &aTag, nsIDOMNode **aResult);
/*END public methods of nsEditor*/
/*BEGIN private methods used by the implementations of the above functions*/ /*BEGIN private methods used by the implementations of the above functions*/
protected: protected:
/** create a transaction for setting aAttribute to aValue on aElement /** create a transaction for setting aAttribute to aValue on aElement
@ -278,28 +256,10 @@ protected:
PRUint32 aOffset, PRUint32 aOffset,
SplitElementTxn **aTxn); SplitElementTxn **aTxn);
NS_IMETHOD SplitNodeImpl(nsIDOMNode * aExistingRightNode,
PRInt32 aOffset,
nsIDOMNode * aNewLeftNode,
nsIDOMNode * aParent);
NS_IMETHOD CreateTxnForJoinNode(nsIDOMNode *aLeftNode, NS_IMETHOD CreateTxnForJoinNode(nsIDOMNode *aLeftNode,
nsIDOMNode *aRightNode, nsIDOMNode *aRightNode,
JoinElementTxn **aTxn); JoinElementTxn **aTxn);
NS_IMETHOD JoinNodesImpl(nsIDOMNode * aNodeToKeep,
nsIDOMNode * aNodeToJoin,
nsIDOMNode * aParent,
PRBool aNodeToKeepIsFirst);
NS_IMETHOD GetPriorNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode);
NS_IMETHOD GetNextNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode);
NS_IMETHOD GetRightmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode);
NS_IMETHOD GetLeftmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode);
/** Create an aggregate transaction for deleting current selection /** Create an aggregate transaction for deleting current selection
* Used by all methods that need to delete current selection, * Used by all methods that need to delete current selection,
* then insert something new to replace it * then insert something new to replace it
@ -321,11 +281,152 @@ protected:
// of an error in Gecko which is not rendering the // of an error in Gecko which is not rendering the
// document after a change via the DOM - gpk 2/13/99 // document after a change via the DOM - gpk 2/13/99
void HACKForceRedraw(void); void HACKForceRedraw(void);
PRBool mIMEFirstTransaction; PRBool mIMEFirstTransaction;
NS_IMETHOD DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNode> &parentSelectedNode, PRInt32& offsetOfNewNode); NS_IMETHOD DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNode> &parentSelectedNode, PRInt32& offsetOfNewNode);
public:
/**
* SplitNode() creates a new node identical to an existing node, and split the contents between the two nodes
* @param aExistingRightNode the node to split. It will become the new node's next sibling.
* @param aOffset the offset of aExistingRightNode's content|children to do the split at
* @param aNewLeftNode [OUT] the new node resulting from the split, becomes aExistingRightNode's previous sibling.
* @param aParent the parent of aExistingRightNode
*/
static nsresult SplitNodeImpl(nsIDOMNode *aExistingRightNode,
PRInt32 aOffset,
nsIDOMNode *aNewLeftNode,
nsIDOMNode *aParent);
/**
* JoinNodes() takes 2 nodes and merge their content|children.
* @param aNodeToKeep The node that will remain after the join.
* @param aNodeToJoin The node that will be joined with aNodeToKeep.
* There is no requirement that the two nodes be of the same type.
* @param aParent The parent of aExistingRightNode
* @param aNodeToKeepIsFirst if PR_TRUE, the contents|children of aNodeToKeep come before the
* contents|children of aNodeToJoin, otherwise their positions are switched.
*/
static nsresult JoinNodesImpl(nsIDOMNode *aNodeToKeep,
nsIDOMNode *aNodeToJoin,
nsIDOMNode *aParent,
PRBool aNodeToKeepIsFirst);
/**
* Set aOffset to the offset of aChild in aParent.
* Returns an error if aChild is not an immediate child of aParent.
*/
static nsresult GetChildOffset(nsIDOMNode *aChild,
nsIDOMNode *aParent,
PRInt32 &aOffset);
/** set aIsInline to PR_TRUE if aNode is inline as defined by HTML DTD */
static nsresult IsNodeInline(nsIDOMNode *aNode, PRBool &aIsInline);
/** returns the closest block parent of aNode, not including aNode itself.
* can return null, for example if aNode is in a document fragment.
* @param aNode The node whose parent we seek.
* @param aBlockParent [OUT] The block parent, if any.
* @return a success value unless an unexpected error occurs.
*/
static nsresult GetBlockParent(nsIDOMNode *aNode,
nsIDOMElement **aBlockParent);
/** Determines the bounding nodes for the block section containing aNode.
* The calculation is based on some nodes intrinsically being block elements
* acording to HTML. Style sheets are not considered in this calculation.
* <BR> tags separate block content sections. So the HTML markup:
* <PRE>
* <P>text1<BR>text2<B>text3</B></P>
* </PRE>
* contains two block content sections. The first has the text node "text1"
* for both endpoints. The second has "text2" as the left endpoint and
* "text3" as the right endpoint.
* Notice that offsets aren't required, only leaf nodes. Offsets are implicit.
*
* @param aNode the block content returned includes aNode
* @param aLeftNode [OUT] the left endpoint of the block content containing aNode
* @param aRightNode [OUT] the right endpoint of the block content containing aNode
*
*/
static nsresult GetBlockSection(nsIDOMNode *aNode,
nsIDOMNode **aLeftNode,
nsIDOMNode **aRightNode);
/** Compute the set of block sections in a given range.
* A block section is the set of (leftNode, rightNode) pairs given
* by GetBlockSection. The set is computed by computing the
* block section for every leaf node in the range and throwing
* out duplicates.
*
* @param aRange The range to compute block sections for.
* @param aSections Allocated storage for the resulting set, stored as nsIDOMRanges.
*/
static nsresult GetBlockSectionsForRange(nsIDOMRange *aRange,
nsISupportsArray *aSections);
/** returns PR_TRUE in out-param aResult if all nodes between (aStartNode, aStartOffset)
* and (aEndNode, aEndOffset) are inline as defined by HTML DTD.
*/
static nsresult IntermediateNodesAreInline(nsIDOMRange *aRange,
nsIDOMNode *aStartNode,
PRInt32 aStartOffset,
nsIDOMNode *aEndNode,
PRInt32 aEndOffset,
PRBool &aResult);
/** returns the number of things inside aNode in the out-param aCount.
* @param aNode is the node to get the length of.
* If aNode is text, returns number of characters.
* If not, returns number of children nodes.
* @param aCount [OUT] the result of the above calculation.
*/
static nsresult GetLengthOfDOMNode(nsIDOMNode *aNode, PRUint32 &aCount);
/**
*/
static nsresult GetPriorNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode);
/**
*/
static nsresult GetNextNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode);
/**
*/
static nsresult GetRightmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode);
/**
*/
static nsresult GetLeftmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode);
/** GetFirstTextNode ADDREFFS and will get the next available text node from the passed
* in node parameter it can also return NS_ERROR_FAILURE if no text nodes are available
* now it simply returns the first node in the dom
* @param nsIDOMNode *aNode is the node to start looking from
* @param nsIDOMNode **aRetNode is the return location of the text dom node
*
* NOTE: this method will probably be removed.
*/
static nsresult GetFirstTextNode(nsIDOMNode *aNode, nsIDOMNode **aRetNode);
/** GetFirstNodeOfType ADDREFFS and will get the next available node from the passed
* in aStartNode parameter of type aTag.
* It can also return NS_ERROR_FAILURE if no such nodes are available
* @param aStartNode is the node to start looking from
* @param aTag is the type of node we are searching for
* @param aResult is the node we found, or nsnull if there is none
*/
static nsresult GetFirstNodeOfType(nsIDOMNode *aStartNode,
const nsString &aTag,
nsIDOMNode **aResult);
/** returns PR_TRUE if aNode is of the type implied by aTag */
static PRBool NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag);
/** returns PR_TRUE if aNode is an editable node */
static PRBool IsEditable(nsIDOMNode *aNode);
}; };

Просмотреть файл

@ -73,6 +73,7 @@ SUP places text in superscript style
// block tags // block tags
static nsIAtom *blockquote; static nsIAtom *blockquote;
static nsIAtom *br;
static nsIAtom *h1; static nsIAtom *h1;
static nsIAtom *h2; static nsIAtom *h2;

Просмотреть файл

@ -43,6 +43,7 @@ nsIAtom * nsIEditProperty::tt;
nsIAtom * nsIEditProperty::u; nsIAtom * nsIEditProperty::u;
// block tags // block tags
nsIAtom * nsIEditProperty::blockquote; nsIAtom * nsIEditProperty::blockquote;
nsIAtom * nsIEditProperty::br;
nsIAtom * nsIEditProperty::h1; nsIAtom * nsIEditProperty::h1;
nsIAtom * nsIEditProperty::h2; nsIAtom * nsIEditProperty::h2;
// properties // properties
@ -56,28 +57,29 @@ void
nsEditProperty::InstanceInit() nsEditProperty::InstanceInit()
{ {
// tags // tags
nsIEditProperty::a = NS_NewAtom("A"); nsIEditProperty::a = NS_NewAtom("a");
nsIEditProperty::b = NS_NewAtom("B"); nsIEditProperty::b = NS_NewAtom("b");
nsIEditProperty::big = NS_NewAtom("BIG"); nsIEditProperty::big = NS_NewAtom("big");
nsIEditProperty::font = NS_NewAtom("FONT"); nsIEditProperty::font = NS_NewAtom("font");
nsIEditProperty::i = NS_NewAtom("I"); nsIEditProperty::i = NS_NewAtom("i");
nsIEditProperty::span = NS_NewAtom("SPAN"); nsIEditProperty::span = NS_NewAtom("span");
nsIEditProperty::small =NS_NewAtom("SMALL"); nsIEditProperty::small =NS_NewAtom("small");
nsIEditProperty::strike=NS_NewAtom("STRIKE"); nsIEditProperty::strike=NS_NewAtom("strike");
nsIEditProperty::sub = NS_NewAtom("SUB"); nsIEditProperty::sub = NS_NewAtom("sub");
nsIEditProperty::sup = NS_NewAtom("SUP"); nsIEditProperty::sup = NS_NewAtom("sup");
nsIEditProperty::tt = NS_NewAtom("TT"); nsIEditProperty::tt = NS_NewAtom("tt");
nsIEditProperty::u = NS_NewAtom("U"); nsIEditProperty::u = NS_NewAtom("u");
// tags // tags
nsIEditProperty::blockquote = NS_NewAtom("BLOCKQUOTE"); nsIEditProperty::blockquote = NS_NewAtom("blockquote");
nsIEditProperty::h1 = NS_NewAtom("H1"); nsIEditProperty::br = NS_NewAtom("br");
nsIEditProperty::h2 = NS_NewAtom("H2"); nsIEditProperty::h1 = NS_NewAtom("h1");
nsIEditProperty::h2 = NS_NewAtom("h2");
// properties // properties
nsIEditProperty::color= NS_NewAtom("COLOR"); nsIEditProperty::color= NS_NewAtom("color");
nsIEditProperty::face = NS_NewAtom("FACE"); nsIEditProperty::face = NS_NewAtom("face");
nsIEditProperty::size = NS_NewAtom("SIZE"); nsIEditProperty::size = NS_NewAtom("size");
// special // special
nsIEditProperty::allProperties = new nsString("moz_AllProperties"); nsIEditProperty::allProperties = new nsString("moz_allproperties");
} }
void void
@ -98,6 +100,7 @@ nsEditProperty::InstanceShutdown()
NS_IF_RELEASE(nsIEditProperty::u); NS_IF_RELEASE(nsIEditProperty::u);
// tags // tags
NS_IF_RELEASE(nsIEditProperty::blockquote); NS_IF_RELEASE(nsIEditProperty::blockquote);
NS_IF_RELEASE(nsIEditProperty::br);
NS_IF_RELEASE(nsIEditProperty::h1); NS_IF_RELEASE(nsIEditProperty::h1);
NS_IF_RELEASE(nsIEditProperty::h2); NS_IF_RELEASE(nsIEditProperty::h2);
// properties // properties

Просмотреть файл

@ -40,7 +40,6 @@
#include "nsIComponentManager.h" #include "nsIComponentManager.h"
#include "nsIServiceManager.h" #include "nsIServiceManager.h"
#include "nsITableCellLayout.h" //For GetColIndexForCell
static NS_DEFINE_IID(kIDOMEventReceiverIID, NS_IDOMEVENTRECEIVER_IID); static NS_DEFINE_IID(kIDOMEventReceiverIID, NS_IDOMEVENTRECEIVER_IID);
@ -59,7 +58,7 @@ static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID);
static NS_DEFINE_IID(kIContentIteratorIID, NS_ICONTENTITERTOR_IID); static NS_DEFINE_IID(kIContentIteratorIID, NS_ICONTENTITERTOR_IID);
#ifdef NS_DEBUG #ifdef NS_DEBUG
static PRBool gNoisy = PR_FALSE; static PRBool gNoisy = PR_TRUE;
#else #else
static const PRBool gNoisy = PR_FALSE; static const PRBool gNoisy = PR_FALSE;
#endif #endif
@ -205,7 +204,7 @@ NS_IMETHODIMP nsHTMLEditor::InsertBreak()
if (-1==offsetInParent) if (-1==offsetInParent)
{ {
nextNode->GetParentNode(getter_AddRefs(parent)); nextNode->GetParentNode(getter_AddRefs(parent));
result = nsIEditorSupport::GetChildOffset(nextNode, parent, offsetInParent); result = GetChildOffset(nextNode, parent, offsetInParent);
if (NS_SUCCEEDED(result)) { if (NS_SUCCEEDED(result)) {
selection->Collapse(parent, offsetInParent+1); // +1 to insert just after the break selection->Collapse(parent, offsetInParent+1); // +1 to insert just after the break
} }
@ -395,17 +394,17 @@ nsHTMLEditor::GetParagraphStyle(nsStringArray *aTagList)
if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem))
{ {
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) ); nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
// scan the range for all the independent block content subranges // scan the range for all the independent block content blockSections
// and get the block parent of each // and get the block parent of each
nsISupportsArray *subRanges; nsISupportsArray *blockSections;
result = NS_NewISupportsArray(&subRanges); result = NS_NewISupportsArray(&blockSections);
if ((NS_SUCCEEDED(result)) && subRanges) if ((NS_SUCCEEDED(result)) && blockSections)
{ {
result = GetBlockRanges(range, subRanges); result = GetBlockSectionsForRange(range, blockSections);
if (NS_SUCCEEDED(result)) if (NS_SUCCEEDED(result))
{ {
nsIDOMRange *subRange; nsIDOMRange *subRange;
subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
while (subRange && (NS_SUCCEEDED(result))) while (subRange && (NS_SUCCEEDED(result)))
{ {
nsCOMPtr<nsIDOMNode>startParent; nsCOMPtr<nsIDOMNode>startParent;
@ -418,17 +417,19 @@ nsHTMLEditor::GetParagraphStyle(nsStringArray *aTagList)
{ {
nsAutoString blockParentTag; nsAutoString blockParentTag;
blockParent->GetTagName(blockParentTag); blockParent->GetTagName(blockParentTag);
if (-1==aTagList->IndexOf(blockParentTag)) { PRBool isRoot;
IsRootTag(blockParentTag, isRoot);
if ((PR_FALSE==isRoot) && (-1==aTagList->IndexOf(blockParentTag))) {
aTagList->AppendString(blockParentTag); aTagList->AppendString(blockParentTag);
} }
} }
} }
NS_RELEASE(subRange); NS_RELEASE(subRange);
subRanges->RemoveElementAt(0); blockSections->RemoveElementAt(0);
subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
} }
} }
NS_RELEASE(subRanges); NS_RELEASE(blockSections);
} }
} }
} }
@ -465,7 +466,7 @@ nsHTMLEditor::AddBlockParent(nsString& aParentTag)
if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem))
{ {
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) ); nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
// scan the range for all the independent block content subranges // scan the range for all the independent block content blockSections
// and apply the transformation to them // and apply the transformation to them
result = ReParentContentOfRange(range, aParentTag, eInsertParent); result = ReParentContentOfRange(range, aParentTag, eInsertParent);
} }
@ -510,47 +511,30 @@ nsHTMLEditor::ReplaceBlockParent(nsString& aParentTag)
if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem))
{ {
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) ); nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
// scan the range for all the independent block content subranges // scan the range for all the independent block content blockSections
// and apply the transformation to them // and apply the transformation to them
result = ReParentContentOfRange(range, aParentTag, eReplaceParent); result = ReParentContentOfRange(range, aParentTag, eReplaceParent);
} }
} }
nsEditor::EndTransaction(); nsEditor::EndTransaction();
if (NS_SUCCEEDED(result))
{ // set the selection
// XXX: can't do anything until I can create ranges
}
} }
if (gNoisy) {printf("Finished nsHTMLEditor::AddBlockParent with this content:\n"); DebugDumpContent(); } // DEBUG if (gNoisy) {printf("Finished nsHTMLEditor::AddBlockParent with this content:\n"); DebugDumpContent(); } // DEBUG
return result; return result;
} }
void IsRootTag(nsString &aTag, PRBool &aIsTag)
{
static nsAutoString bodyTag = "body";
static nsAutoString tdTag = "td";
static nsAutoString thTag = "th";
static nsAutoString captionTag = "caption";
if (PR_TRUE==aTag.EqualsIgnoreCase(bodyTag) ||
PR_TRUE==aTag.EqualsIgnoreCase(tdTag) ||
PR_TRUE==aTag.EqualsIgnoreCase(thTag) ||
PR_TRUE==aTag.EqualsIgnoreCase(captionTag) )
{
aIsTag = PR_TRUE;
}
else {
aIsTag = PR_FALSE;
}
}
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode, nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode,
nsString &aParentTag, nsString &aParentTag,
BlockTransformationType aTransformation) BlockTransformationType aTransformation)
{ {
if (!aNode) { return NS_ERROR_NULL_POINTER; } if (!aNode) { return NS_ERROR_NULL_POINTER; }
if (gNoisy)
{
char *tag = aParentTag.ToNewCString();
printf("---------- ReParentContentOfNode(%p,%s,%d) -----------\n", aNode, tag, aTransformation);
delete [] tag;
}
// find the current block parent, or just use aNode if it is a block node // find the current block parent, or just use aNode if it is a block node
nsCOMPtr<nsIDOMElement>blockParentElement; nsCOMPtr<nsIDOMElement>blockParentElement;
nsCOMPtr<nsIDOMNode>nodeToReParent; // this is the node we'll operate on, by default it's aNode nsCOMPtr<nsIDOMNode>nodeToReParent; // this is the node we'll operate on, by default it's aNode
@ -606,7 +590,7 @@ nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode,
{ // this is the case of an insertion point between 2 non-text objects { // this is the case of an insertion point between 2 non-text objects
// XXX: how to you know it's an insertion point??? // XXX: how to you know it's an insertion point???
PRInt32 offsetInParent=0; PRInt32 offsetInParent=0;
result = nsIEditorSupport::GetChildOffset(nodeToReParent, blockParentNode, offsetInParent); result = GetChildOffset(nodeToReParent, blockParentNode, offsetInParent);
NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset"); NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset");
// otherwise, just create the block parent at the selection // otherwise, just create the block parent at the selection
result = nsTextEditor::CreateNode(aParentTag, blockParentNode, offsetInParent, result = nsTextEditor::CreateNode(aParentTag, blockParentNode, offsetInParent,
@ -654,10 +638,14 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode,
nsString &aParentTag, nsString &aParentTag,
nsIDOMNode *aBlockParentNode, nsIDOMNode *aBlockParentNode,
nsString &aBlockParentTag, nsString &aBlockParentTag,
BlockTransformationType aTranformation, BlockTransformationType aTransformation,
nsIDOMNode **aNewParentNode) nsIDOMNode **aNewParentNode)
{ {
if (!aNode || !aBlockParentNode || !aNewParentNode) { return NS_ERROR_NULL_POINTER; } if (!aNode || !aBlockParentNode || !aNewParentNode) { return NS_ERROR_NULL_POINTER; }
nsCOMPtr<nsIDOMNode> blockParentNode = do_QueryInterface(aBlockParentNode);
PRBool removeBlockParent = PR_FALSE;
PRBool removeBreakBefore = PR_FALSE;
PRBool removeBreakAfter = PR_FALSE;
nsCOMPtr<nsIDOMNode>ancestor; nsCOMPtr<nsIDOMNode>ancestor;
nsresult result = aNode->GetParentNode(getter_AddRefs(ancestor)); nsresult result = aNode->GetParentNode(getter_AddRefs(ancestor));
nsCOMPtr<nsIDOMNode>previousAncestor = do_QueryInterface(aNode); nsCOMPtr<nsIDOMNode>previousAncestor = do_QueryInterface(aNode);
@ -675,46 +663,87 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode,
} }
// now, previousAncestor is the node we are operating on // now, previousAncestor is the node we are operating on
nsCOMPtr<nsIDOMNode>leftNode, rightNode; nsCOMPtr<nsIDOMNode>leftNode, rightNode;
result = GetBlockDelimitedContent(previousAncestor, result = GetBlockSection(previousAncestor,
getter_AddRefs(leftNode), getter_AddRefs(leftNode),
getter_AddRefs(rightNode)); getter_AddRefs(rightNode));
if ((NS_SUCCEEDED(result)) && leftNode && rightNode) if ((NS_SUCCEEDED(result)) && leftNode && rightNode)
{ {
PRInt32 offsetInParent=0; // determine some state for managing <BR>s around the new block
if (eInsertParent==aTranformation) PRBool isSubordinateBlock = PR_FALSE; // if true, the content is already in a subordinate block
PRBool isRootBlock = PR_FALSE; // if true, the content is in a root block
nsCOMPtr<nsIDOMElement>blockParentElement = do_QueryInterface(blockParentNode);
if (blockParentElement)
{ {
result = nsIEditorSupport::GetChildOffset(leftNode, aBlockParentNode, offsetInParent); nsAutoString blockParentTag;
blockParentElement->GetTagName(blockParentTag);
IsSubordinateBlock(blockParentTag, isSubordinateBlock);
IsRootTag(blockParentTag, isRootBlock);
}
if (PR_TRUE==isRootBlock)
{ // we're creating a block element where a block element did not previously exist
removeBreakBefore = PR_TRUE;
removeBreakAfter = PR_TRUE;
}
// apply the transformation
PRInt32 offsetInParent=0;
if (eInsertParent==aTransformation || PR_TRUE==isRootBlock)
{
result = GetChildOffset(leftNode, blockParentNode, offsetInParent);
NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset"); NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset");
result = nsTextEditor::CreateNode(aParentTag, aBlockParentNode, offsetInParent, aNewParentNode); result = nsTextEditor::CreateNode(aParentTag, blockParentNode, offsetInParent, aNewParentNode);
if (gNoisy) { printf("created a node in aBlockParentNode at offset %d\n", offsetInParent); } if (gNoisy) { printf("created a node in blockParentNode at offset %d\n", offsetInParent); }
} }
else else
{ {
nsCOMPtr<nsIDOMNode> grandParent; nsCOMPtr<nsIDOMNode> grandParent;
result = aBlockParentNode->GetParentNode(getter_AddRefs(grandParent)); result = blockParentNode->GetParentNode(getter_AddRefs(grandParent));
if ((NS_SUCCEEDED(result)) && grandParent) if ((NS_SUCCEEDED(result)) && grandParent)
{ {
nsCOMPtr<nsIDOMNode>firstChildNode, lastChildNode; nsCOMPtr<nsIDOMNode>firstChildNode, lastChildNode;
aBlockParentNode->GetFirstChild(getter_AddRefs(firstChildNode)); blockParentNode->GetFirstChild(getter_AddRefs(firstChildNode));
aBlockParentNode->GetLastChild(getter_AddRefs(lastChildNode)); blockParentNode->GetLastChild(getter_AddRefs(lastChildNode));
if (firstChildNode==leftNode && lastChildNode==rightNode) if (firstChildNode==leftNode && lastChildNode==rightNode)
{ {
result = nsIEditorSupport::GetChildOffset(aBlockParentNode, grandParent, offsetInParent); result = GetChildOffset(blockParentNode, grandParent, offsetInParent);
NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset"); NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset");
result = nsTextEditor::CreateNode(aParentTag, grandParent, offsetInParent, aNewParentNode); result = nsTextEditor::CreateNode(aParentTag, grandParent, offsetInParent, aNewParentNode);
if (gNoisy) { printf("created a node in grandParent at offset %d\n", offsetInParent); } if (gNoisy) { printf("created a node in grandParent at offset %d\n", offsetInParent); }
} }
else else
{ {
result = nsIEditorSupport::GetChildOffset(leftNode, aBlockParentNode, offsetInParent); // We're in the case where the content of blockParentNode is separated by <BR>'s,
// creating multiple block content ranges.
// Split blockParentNode around the blockContent
if (gNoisy) { printf("splitting a node because of <BR>s\n"); }
nsCOMPtr<nsIDOMNode> newLeftNode;
if (firstChildNode!=leftNode)
{
result = GetChildOffset(leftNode, blockParentNode, offsetInParent);
if (gNoisy) { printf("splitting left at %d\n", offsetInParent); }
result = SplitNode(blockParentNode, offsetInParent, getter_AddRefs(newLeftNode));
// after this split, blockParentNode still contains leftNode and rightNode
}
if (lastChildNode!=rightNode)
{
result = GetChildOffset(rightNode, blockParentNode, offsetInParent);
offsetInParent++;
if (gNoisy) { printf("splitting right at %d\n", offsetInParent); }
result = SplitNode(blockParentNode, offsetInParent, getter_AddRefs(newLeftNode));
blockParentNode = do_QueryInterface(newLeftNode);
}
result = GetChildOffset(leftNode, blockParentNode, offsetInParent);
NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset"); NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset");
result = nsTextEditor::CreateNode(aParentTag, aBlockParentNode, offsetInParent, aNewParentNode); result = nsTextEditor::CreateNode(aParentTag, blockParentNode, offsetInParent, aNewParentNode);
if (gNoisy) { printf("created a node in aBlockParentNode at offset %d\n", offsetInParent); } if (gNoisy) { printf("created a node in blockParentNode at offset %d\n", offsetInParent); }
// what we need to do here is remove the existing block parent when we're all done.
removeBlockParent = PR_TRUE;
} }
} }
} }
if ((NS_SUCCEEDED(result)) && *aNewParentNode) if ((NS_SUCCEEDED(result)) && *aNewParentNode)
{ // move all the children/contents of aBlockParentNode to aNewParentNode { // move all the children/contents of blockParentNode to aNewParentNode
nsCOMPtr<nsIDOMNode>childNode = do_QueryInterface(rightNode); nsCOMPtr<nsIDOMNode>childNode = do_QueryInterface(rightNode);
nsCOMPtr<nsIDOMNode>previousSiblingNode; nsCOMPtr<nsIDOMNode>previousSiblingNode;
while (NS_SUCCEEDED(result) && childNode) while (NS_SUCCEEDED(result) && childNode)
@ -737,6 +766,73 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode,
childNode = do_QueryInterface(previousSiblingNode); childNode = do_QueryInterface(previousSiblingNode);
} // end while loop } // end while loop
} }
// clean up the surrounding content to maintain vertical whitespace
if (NS_SUCCEEDED(result))
{
// if the prior node is a <BR> and we did something to change vertical whitespacing, delete the <BR>
nsCOMPtr<nsIDOMNode> brNode;
result = GetPriorNode(leftNode, getter_AddRefs(brNode));
if (NS_SUCCEEDED(result) && brNode)
{
nsCOMPtr<nsIContent> brContent = do_QueryInterface(brNode);
if (brContent)
{
nsCOMPtr<nsIAtom> brContentTag;
brContent->GetTag(*getter_AddRefs(brContentTag));
if (nsIEditProperty::br==brContentTag) {
result = DeleteNode(brNode);
}
}
}
// if the next node is a <BR> and we did something to change vertical whitespacing, delete the <BR>
if (NS_SUCCEEDED(result))
{
result = GetNextNode(rightNode, getter_AddRefs(brNode));
if (NS_SUCCEEDED(result) && brNode)
{
nsCOMPtr<nsIContent> brContent = do_QueryInterface(brNode);
if (brContent)
{
nsCOMPtr<nsIAtom> brContentTag;
brContent->GetTag(*getter_AddRefs(brContentTag));
if (nsIEditProperty::br==brContentTag) {
result = DeleteNode(brNode);
}
}
}
}
}
if ((NS_SUCCEEDED(result)) && (PR_TRUE==removeBlockParent))
{ // we determined we need to remove the previous block parent. Do it!
// go through list backwards so deletes don't interfere with the iteration
nsCOMPtr<nsIDOMNodeList> childNodes;
result = blockParentNode->GetChildNodes(getter_AddRefs(childNodes));
if ((NS_SUCCEEDED(result)) && (childNodes))
{
nsCOMPtr<nsIDOMNode>grandParent;
blockParentNode->GetParentNode(getter_AddRefs(grandParent));
PRInt32 offsetInParent;
result = GetChildOffset(blockParentNode, grandParent, offsetInParent);
PRUint32 childCount;
childNodes->GetLength(&childCount);
PRInt32 i=childCount-1;
for ( ; ((NS_SUCCEEDED(result)) && (0<=i)); i--)
{
nsCOMPtr<nsIDOMNode> childNode;
result = childNodes->Item(i, getter_AddRefs(childNode));
if ((NS_SUCCEEDED(result)) && (childNode))
{
result = nsTextEditor::DeleteNode(childNode);
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::InsertNode(childNode, grandParent, offsetInParent);
}
}
}
if (gNoisy) { printf("removing the old block parent %p\n", blockParentNode.get()); }
result = nsTextEditor::DeleteNode(blockParentNode);
}
}
} }
return result; return result;
} }
@ -748,29 +844,30 @@ nsHTMLEditor::ReParentContentOfRange(nsIDOMRange *aRange,
{ {
if (!aRange) { return NS_ERROR_NULL_POINTER; } if (!aRange) { return NS_ERROR_NULL_POINTER; }
nsresult result; nsresult result;
nsISupportsArray *subRanges; nsISupportsArray *blockSections;
result = NS_NewISupportsArray(&subRanges); result = NS_NewISupportsArray(&blockSections);
if ((NS_SUCCEEDED(result)) && subRanges) if ((NS_SUCCEEDED(result)) && blockSections)
{ {
result = GetBlockRanges(aRange, subRanges); result = GetBlockSectionsForRange(aRange, blockSections);
if (NS_SUCCEEDED(result)) if (NS_SUCCEEDED(result))
{ {
nsIDOMRange *subRange; nsIDOMRange *subRange;
subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
while (subRange && (NS_SUCCEEDED(result))) while (subRange && (NS_SUCCEEDED(result)))
{ {
nsCOMPtr<nsIDOMNode>startParent; nsCOMPtr<nsIDOMNode>startParent;
result = subRange->GetStartParent(getter_AddRefs(startParent)); result = subRange->GetStartParent(getter_AddRefs(startParent));
if (NS_SUCCEEDED(result) && startParent) if (NS_SUCCEEDED(result) && startParent)
{ {
if (gNoisy) { printf("ReParentContentOfRange calling ReParentContentOfNode\n"); }
result = ReParentContentOfNode(startParent, aParentTag, aTranformation); result = ReParentContentOfNode(startParent, aParentTag, aTranformation);
} }
NS_RELEASE(subRange); NS_RELEASE(subRange);
subRanges->RemoveElementAt(0); blockSections->RemoveElementAt(0);
subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
} }
} }
NS_RELEASE(subRanges); NS_RELEASE(blockSections);
} }
return result; return result;
} }
@ -793,10 +890,10 @@ nsHTMLEditor::CanContainBlock(nsString &aBlockChild, nsString &aBlockParent, PRB
} }
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLEditor::RemoveBlockParent() nsHTMLEditor::RemoveParagraphStyle()
{ {
if (gNoisy) { if (gNoisy) {
printf("---------- nsHTMLEditor::RemoveBlockParent ----------\n"); printf("---------- nsHTMLEditor::RemoveParagraphStyle ----------\n");
} }
nsresult result=NS_ERROR_NOT_INITIALIZED; nsresult result=NS_ERROR_NOT_INITIALIZED;
@ -815,65 +912,7 @@ nsHTMLEditor::RemoveBlockParent()
if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem))
{ {
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) ); nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
nsCOMPtr<nsIDOMNode>commonParent; result = RemoveParagraphStyleFromRange(range);
result = range->GetCommonParent(getter_AddRefs(commonParent));
if ((NS_SUCCEEDED(result)) && commonParent)
{
PRInt32 startOffset, endOffset;
range->GetStartOffset(&startOffset);
range->GetEndOffset(&endOffset);
nsCOMPtr<nsIDOMNode> startParent; nsCOMPtr<nsIDOMNode> endParent;
range->GetStartParent(getter_AddRefs(startParent));
range->GetEndParent(getter_AddRefs(endParent));
if (startParent.get()==endParent.get())
{ // the range is entirely contained within a single node
nsCOMPtr<nsIDOMElement>blockParentElement;
result = nsTextEditor::GetBlockParent(startParent, getter_AddRefs(blockParentElement));
while ((NS_SUCCEEDED(result)) && blockParentElement)
{
nsAutoString childTag; // leave as empty string
nsAutoString blockParentTag;
blockParentElement->GetTagName(blockParentTag);
PRBool canContain;
CanContainBlock(childTag, blockParentTag, canContain);
if (PR_TRUE==canContain) {
break;
}
else
{
// go through list backwards so deletes don't interfere with the iteration
nsCOMPtr<nsIDOMNodeList> childNodes;
result = blockParentElement->GetChildNodes(getter_AddRefs(childNodes));
if ((NS_SUCCEEDED(result)) && (childNodes))
{
nsCOMPtr<nsIDOMNode>grandParent;
blockParentElement->GetParentNode(getter_AddRefs(grandParent));
PRInt32 offsetInParent;
result = nsIEditorSupport::GetChildOffset(blockParentElement, grandParent, offsetInParent);
PRUint32 childCount;
childNodes->GetLength(&childCount);
PRInt32 i=childCount-1;
for ( ; ((NS_SUCCEEDED(result)) && (0<=i)); i--)
{
nsCOMPtr<nsIDOMNode> childNode;
result = childNodes->Item(i, getter_AddRefs(childNode));
if ((NS_SUCCEEDED(result)) && (childNode))
{
result = nsTextEditor::DeleteNode(childNode);
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::InsertNode(childNode, grandParent, offsetInParent);
}
}
}
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::DeleteNode(blockParentElement);
}
}
}
result = nsTextEditor::GetBlockParent(startParent, getter_AddRefs(blockParentElement));
}
}
}
} }
} }
nsEditor::EndTransaction(); nsEditor::EndTransaction();
@ -881,11 +920,93 @@ nsHTMLEditor::RemoveBlockParent()
return result; return result;
} }
NS_IMETHODIMP
nsHTMLEditor::RemoveParagraphStyleFromRange(nsIDOMRange *aRange)
{
if (!aRange) { return NS_ERROR_NULL_POINTER; }
nsresult result;
nsISupportsArray *blockSections;
result = NS_NewISupportsArray(&blockSections);
if ((NS_SUCCEEDED(result)) && blockSections)
{
result = GetBlockSectionsForRange(aRange, blockSections);
if (NS_SUCCEEDED(result))
{
nsIDOMRange *subRange;
subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
while (subRange && (NS_SUCCEEDED(result)))
{
result = RemoveParagraphStyleFromBlockContent(subRange);
NS_RELEASE(subRange);
blockSections->RemoveElementAt(0);
subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
}
}
NS_RELEASE(blockSections);
}
return result;
}
NS_IMETHODIMP
nsHTMLEditor::RemoveParagraphStyleFromBlockContent(nsIDOMRange *aRange)
{
if (!aRange) { return NS_ERROR_NULL_POINTER; }
nsresult result;
nsCOMPtr<nsIDOMNode>startParent;
aRange->GetStartParent(getter_AddRefs(startParent));
nsCOMPtr<nsIDOMElement>blockParentElement;
result = nsTextEditor::GetBlockParent(startParent, getter_AddRefs(blockParentElement));
while ((NS_SUCCEEDED(result)) && blockParentElement)
{
nsAutoString blockParentTag;
blockParentElement->GetTagName(blockParentTag);
PRBool isSubordinateBlock;
IsSubordinateBlock(blockParentTag, isSubordinateBlock);
if (PR_FALSE==isSubordinateBlock) {
break;
}
else
{
// go through list backwards so deletes don't interfere with the iteration
nsCOMPtr<nsIDOMNodeList> childNodes;
result = blockParentElement->GetChildNodes(getter_AddRefs(childNodes));
if ((NS_SUCCEEDED(result)) && (childNodes))
{
nsCOMPtr<nsIDOMNode>grandParent;
blockParentElement->GetParentNode(getter_AddRefs(grandParent));
PRInt32 offsetInParent;
result = GetChildOffset(blockParentElement, grandParent, offsetInParent);
PRUint32 childCount;
childNodes->GetLength(&childCount);
PRInt32 i=childCount-1;
for ( ; ((NS_SUCCEEDED(result)) && (0<=i)); i--)
{
nsCOMPtr<nsIDOMNode> childNode;
result = childNodes->Item(i, getter_AddRefs(childNode));
if ((NS_SUCCEEDED(result)) && (childNode))
{
result = nsTextEditor::DeleteNode(childNode);
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::InsertNode(childNode, grandParent, offsetInParent);
}
}
}
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::DeleteNode(blockParentElement);
}
}
}
result = nsTextEditor::GetBlockParent(startParent, getter_AddRefs(blockParentElement));
}
return result;
}
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLEditor::RemoveParent(const nsString &aParentTag) nsHTMLEditor::RemoveParent(const nsString &aParentTag)
{ {
if (gNoisy) { if (gNoisy) {
printf("---------- nsHTMLEditor::RemoveParent %s----------\n", aParentTag); printf("---------- nsHTMLEditor::RemoveParagraphStyle ----------\n");
} }
nsresult result=NS_ERROR_NOT_INITIALIZED; nsresult result=NS_ERROR_NOT_INITIALIZED;
@ -904,68 +1025,7 @@ nsHTMLEditor::RemoveParent(const nsString &aParentTag)
if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem))
{ {
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) ); nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
nsCOMPtr<nsIDOMNode>commonParent; result = RemoveParentFromRange(aParentTag, range);
result = range->GetCommonParent(getter_AddRefs(commonParent));
if ((NS_SUCCEEDED(result)) && commonParent)
{
PRInt32 startOffset, endOffset;
range->GetStartOffset(&startOffset);
range->GetEndOffset(&endOffset);
nsCOMPtr<nsIDOMNode> startParent; nsCOMPtr<nsIDOMNode> endParent;
range->GetStartParent(getter_AddRefs(startParent));
range->GetEndParent(getter_AddRefs(endParent));
if (startParent.get()==endParent.get())
{ // the range is entirely contained within a single node
nsCOMPtr<nsIDOMNode>parentNode;
nsCOMPtr<nsIDOMElement>parentElement;
result = startParent->GetParentNode(getter_AddRefs(parentNode));
while ((NS_SUCCEEDED(result)) && parentNode)
{
parentElement = do_QueryInterface(parentNode);
nsAutoString childTag; // leave as empty string
nsAutoString parentTag;
parentElement->GetTagName(parentTag);
PRBool canContain;
CanContainBlock(childTag, parentTag, canContain);
if (aParentTag.EqualsIgnoreCase(parentTag))
{
// go through list backwards so deletes don't interfere with the iteration
nsCOMPtr<nsIDOMNodeList> childNodes;
result = parentElement->GetChildNodes(getter_AddRefs(childNodes));
if ((NS_SUCCEEDED(result)) && (childNodes))
{
nsCOMPtr<nsIDOMNode>grandParent;
parentElement->GetParentNode(getter_AddRefs(grandParent));
PRInt32 offsetInParent;
result = nsIEditorSupport::GetChildOffset(parentElement, grandParent, offsetInParent);
PRUint32 childCount;
childNodes->GetLength(&childCount);
PRInt32 i=childCount-1;
for ( ; ((NS_SUCCEEDED(result)) && (0<=i)); i--)
{
nsCOMPtr<nsIDOMNode> childNode;
result = childNodes->Item(i, getter_AddRefs(childNode));
if ((NS_SUCCEEDED(result)) && (childNode))
{
result = nsTextEditor::DeleteNode(childNode);
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::InsertNode(childNode, grandParent, offsetInParent);
}
}
}
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::DeleteNode(parentElement);
}
}
break;
}
else if (PR_TRUE==canContain) { // hit a subdoc, terminate?
break;
}
result = parentElement->GetParentNode(getter_AddRefs(parentNode));
}
}
}
} }
} }
nsEditor::EndTransaction(); nsEditor::EndTransaction();
@ -973,6 +1033,92 @@ nsHTMLEditor::RemoveParent(const nsString &aParentTag)
return result; return result;
} }
NS_IMETHODIMP
nsHTMLEditor::RemoveParentFromRange(const nsString &aParentTag, nsIDOMRange *aRange)
{
if (!aRange) { return NS_ERROR_NULL_POINTER; }
nsresult result;
nsISupportsArray *blockSections;
result = NS_NewISupportsArray(&blockSections);
if ((NS_SUCCEEDED(result)) && blockSections)
{
result = GetBlockSectionsForRange(aRange, blockSections);
if (NS_SUCCEEDED(result))
{
nsIDOMRange *subRange;
subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
while (subRange && (NS_SUCCEEDED(result)))
{
result = RemoveParentFromBlockContent(aParentTag, subRange);
NS_RELEASE(subRange);
blockSections->RemoveElementAt(0);
subRange = (nsIDOMRange *)(blockSections->ElementAt(0));
}
}
NS_RELEASE(blockSections);
}
return result;
}
NS_IMETHODIMP
nsHTMLEditor::RemoveParentFromBlockContent(const nsString &aParentTag, nsIDOMRange *aRange)
{
if (!aRange) { return NS_ERROR_NULL_POINTER; }
nsresult result;
nsCOMPtr<nsIDOMNode>startParent;
result = aRange->GetStartParent(getter_AddRefs(startParent));
if ((NS_SUCCEEDED(result)) && startParent)
{
nsCOMPtr<nsIDOMNode>parentNode;
nsCOMPtr<nsIDOMElement>parentElement;
result = startParent->GetParentNode(getter_AddRefs(parentNode));
while ((NS_SUCCEEDED(result)) && parentNode)
{
parentElement = do_QueryInterface(parentNode);
nsAutoString parentTag;
parentElement->GetTagName(parentTag);
PRBool isRoot;
IsRootTag(parentTag, isRoot);
if (aParentTag.EqualsIgnoreCase(parentTag))
{
// go through list backwards so deletes don't interfere with the iteration
nsCOMPtr<nsIDOMNodeList> childNodes;
result = parentElement->GetChildNodes(getter_AddRefs(childNodes));
if ((NS_SUCCEEDED(result)) && (childNodes))
{
nsCOMPtr<nsIDOMNode>grandParent;
parentElement->GetParentNode(getter_AddRefs(grandParent));
PRInt32 offsetInParent;
result = GetChildOffset(parentElement, grandParent, offsetInParent);
PRUint32 childCount;
childNodes->GetLength(&childCount);
PRInt32 i=childCount-1;
for ( ; ((NS_SUCCEEDED(result)) && (0<=i)); i--)
{
nsCOMPtr<nsIDOMNode> childNode;
result = childNodes->Item(i, getter_AddRefs(childNode));
if ((NS_SUCCEEDED(result)) && (childNode))
{
result = nsTextEditor::DeleteNode(childNode);
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::InsertNode(childNode, grandParent, offsetInParent);
}
}
}
if (NS_SUCCEEDED(result)) {
result = nsTextEditor::DeleteNode(parentElement);
}
}
break;
}
else if (PR_TRUE==isRoot) { // hit a local root node, terminate loop
break;
}
result = parentElement->GetParentNode(getter_AddRefs(parentNode));
}
}
return result;
}
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLEditor::InsertLink(nsString& aURL) nsHTMLEditor::InsertLink(nsString& aURL)
@ -1331,6 +1477,62 @@ nsHTMLEditor::InsertElement(nsIDOMElement* aElement, PRBool aDeleteSelection, ns
return result; return result;
} }
NS_IMETHODIMP
nsHTMLEditor::IsRootTag(nsString &aTag, PRBool &aIsTag)
{
static nsAutoString bodyTag = "body";
static nsAutoString tdTag = "td";
static nsAutoString thTag = "th";
static nsAutoString captionTag = "caption";
if (PR_TRUE==aTag.EqualsIgnoreCase(bodyTag) ||
PR_TRUE==aTag.EqualsIgnoreCase(tdTag) ||
PR_TRUE==aTag.EqualsIgnoreCase(thTag) ||
PR_TRUE==aTag.EqualsIgnoreCase(captionTag) )
{
aIsTag = PR_TRUE;
}
else {
aIsTag = PR_FALSE;
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLEditor::IsSubordinateBlock(nsString &aTag, PRBool &aIsTag)
{
static nsAutoString p = "p";
static nsAutoString h1 = "h1";
static nsAutoString h2 = "h2";
static nsAutoString h3 = "h3";
static nsAutoString h4 = "h4";
static nsAutoString h5 = "h5";
static nsAutoString h6 = "h6";
static nsAutoString address = "address";
static nsAutoString pre = "pre";
static nsAutoString li = "li";
static nsAutoString dt = "dt";
static nsAutoString dd = "dd";
if (PR_TRUE==aTag.EqualsIgnoreCase(p) ||
PR_TRUE==aTag.EqualsIgnoreCase(h1) ||
PR_TRUE==aTag.EqualsIgnoreCase(h2) ||
PR_TRUE==aTag.EqualsIgnoreCase(h3) ||
PR_TRUE==aTag.EqualsIgnoreCase(h4) ||
PR_TRUE==aTag.EqualsIgnoreCase(h5) ||
PR_TRUE==aTag.EqualsIgnoreCase(h6) ||
PR_TRUE==aTag.EqualsIgnoreCase(address) ||
PR_TRUE==aTag.EqualsIgnoreCase(pre) ||
PR_TRUE==aTag.EqualsIgnoreCase(li) ||
PR_TRUE==aTag.EqualsIgnoreCase(dt) ||
PR_TRUE==aTag.EqualsIgnoreCase(dd) )
{
aIsTag = PR_TRUE;
}
else {
aIsTag = PR_FALSE;
}
return NS_OK;
}
NS_IMETHODIMP nsHTMLEditor::BeginComposition(void) NS_IMETHODIMP nsHTMLEditor::BeginComposition(void)
{ {
return nsTextEditor::BeginComposition(); return nsTextEditor::BeginComposition();
@ -1344,4 +1546,4 @@ NS_IMETHODIMP nsHTMLEditor::EndComposition(void)
NS_IMETHODIMP nsHTMLEditor::SetCompositionString(const nsString& aCompositionString) NS_IMETHODIMP nsHTMLEditor::SetCompositionString(const nsString& aCompositionString)
{ {
return nsTextEditor::SetCompositionString(aCompositionString); return nsTextEditor::SetCompositionString(aCompositionString);
} }

Просмотреть файл

@ -107,7 +107,7 @@ public:
NS_IMETHOD GetParagraphStyle(nsStringArray *aTagList); NS_IMETHOD GetParagraphStyle(nsStringArray *aTagList);
NS_IMETHOD AddBlockParent(nsString& aParentTag); NS_IMETHOD AddBlockParent(nsString& aParentTag);
NS_IMETHOD ReplaceBlockParent(nsString& aParentTag); NS_IMETHOD ReplaceBlockParent(nsString& aParentTag);
NS_IMETHOD RemoveBlockParent(); NS_IMETHOD RemoveParagraphStyle();
NS_IMETHOD RemoveParent(const nsString &aParentTag); NS_IMETHOD RemoveParent(const nsString &aParentTag);
NS_IMETHOD InsertLink(nsString& aURL); NS_IMETHOD InsertLink(nsString& aURL);
@ -163,8 +163,22 @@ protected:
nsString &aParentTag, nsString &aParentTag,
BlockTransformationType aTranformation); BlockTransformationType aTranformation);
NS_IMETHOD RemoveParagraphStyleFromRange(nsIDOMRange *aRange);
NS_IMETHOD RemoveParagraphStyleFromBlockContent(nsIDOMRange *aRange);
NS_IMETHOD RemoveParentFromRange(const nsString &aParentTag, nsIDOMRange *aRange);
NS_IMETHOD RemoveParentFromBlockContent(const nsString &aParentTag, nsIDOMRange *aRange);
NS_IMETHOD CanContainBlock(nsString &aBlockChild, nsString &aBlockParent, PRBool &aCanContain); NS_IMETHOD CanContainBlock(nsString &aBlockChild, nsString &aBlockParent, PRBool &aCanContain);
NS_IMETHOD IsRootTag(nsString &aTag, PRBool &aIsTag);
NS_IMETHOD IsSubordinateBlock(nsString &aTag, PRBool &aIsTag);
// EVENT LISTENERS AND COMMAND ROUTING NEEDS WORK // EVENT LISTENERS AND COMMAND ROUTING NEEDS WORK
// For now, the listners are tied to the nsTextEditor class // For now, the listners are tied to the nsTextEditor class
// //

Просмотреть файл

@ -25,6 +25,7 @@
#include "nsIDOMCharacterData.h" #include "nsIDOMCharacterData.h"
#include "nsIEditProperty.h" #include "nsIEditProperty.h"
#include "nsISupportsArray.h" #include "nsISupportsArray.h"
#include "nsVoidArray.h"
#include "nsString.h" #include "nsString.h"
#include "nsIStringStream.h" #include "nsIStringStream.h"
@ -599,7 +600,39 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr
nsCOMPtr<nsIHTMLEditor>htmlEditor; nsCOMPtr<nsIHTMLEditor>htmlEditor;
htmlEditor = do_QueryInterface(mEditor); htmlEditor = do_QueryInterface(mEditor);
if (htmlEditor) { if (htmlEditor) {
htmlEditor->RemoveBlockParent(); htmlEditor->RemoveParagraphStyle();
}
}
}
break;
// hard-coded change structure test -- GetParagraphStyle
case nsIDOMEvent::VK_0:
if (PR_TRUE==ctrlKey)
{
aProcessed=PR_TRUE;
if (mEditor)
{
nsCOMPtr<nsIHTMLEditor>htmlEditor;
htmlEditor = do_QueryInterface(mEditor);
if (htmlEditor)
{
printf("testing GetParagraphStyle\n");
nsStringArray styles;
nsresult result = htmlEditor->GetParagraphStyle(&styles);
if (NS_SUCCEEDED(result))
{
PRInt32 count = styles.Count();
PRInt32 i;
for (i=0; i<count; i++)
{
nsString *tag = styles.StringAt(i);
char *tagCString = tag->ToNewCString();
printf("%s ", tagCString);
delete [] tagCString;
}
printf("\n");
}
} }
} }
} }

Просмотреть файл

@ -18,6 +18,7 @@
#include "nsTextEditRules.h" #include "nsTextEditRules.h"
#include "nsTextEditor.h" #include "nsTextEditor.h"
#include "nsEditor.h"
#include "PlaceholderTxn.h" #include "PlaceholderTxn.h"
#include "InsertTextTxn.h" #include "InsertTextTxn.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
@ -31,69 +32,8 @@
#include "nsIContent.h" #include "nsIContent.h"
#include "nsIEditProperty.h" #include "nsIEditProperty.h"
const static char* kMOZEditorBogusNodeAttr="MOZ_EDITOR_BOGUS_NODE";
const static char* kMOZEditorBogusNodeValue="TRUE";
static NS_DEFINE_IID(kPlaceholderTxnIID, PLACEHOLDER_TXN_IID); static NS_DEFINE_IID(kPlaceholderTxnIID, PLACEHOLDER_TXN_IID);
/********************************************************
* Helper Functions
********************************************************/
PRBool nsTextEditRules::NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag)
{
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(aNode);
if (element)
{
nsAutoString tag;
element->GetTagName(tag);
if (tag.Equals(aTag->GetUnicode()))
{
return PR_TRUE;
}
}
return PR_FALSE;
}
PRBool nsTextEditRules::IsEditable(nsIDOMNode *aNode)
{
if (!aNode) return PR_FALSE;
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(aNode);
if (element)
{
nsAutoString att(kMOZEditorBogusNodeAttr);
nsAutoString val;
(void)element->GetAttribute(att, val);
if (val.Equals(kMOZEditorBogusNodeValue)) {
return PR_FALSE;
}
else {
return PR_TRUE;
}
}
else
{
nsCOMPtr<nsIDOMCharacterData>text;
text = do_QueryInterface(aNode);
if (text)
{
nsAutoString data;
text->GetData(data);
if (0==data.Length()) {
return PR_FALSE;
}
if ('\n'==data.CharAt(0)) {
return PR_FALSE;
}
else {
return PR_TRUE;
}
}
}
return PR_TRUE;
}
/******************************************************** /********************************************************
@ -437,7 +377,7 @@ nsTextEditRules::InsertStyleNode(nsIDOMNode *aNode,
nsCOMPtr<nsIDOMNode>parent; nsCOMPtr<nsIDOMNode>parent;
aNode->GetParentNode(getter_AddRefs(parent)); aNode->GetParentNode(getter_AddRefs(parent));
PRInt32 offsetInParent; PRInt32 offsetInParent;
nsIEditorSupport::GetChildOffset(aNode, parent, offsetInParent); nsEditor::GetChildOffset(aNode, parent, offsetInParent);
nsAutoString tag; nsAutoString tag;
aTag->ToString(tag); aTag->ToString(tag);
result = mEditor->CreateNode(tag, parent, offsetInParent, aNewNode); result = mEditor->CreateNode(tag, parent, offsetInParent, aNewNode);
@ -563,7 +503,7 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection, nsresult aResul
result = bodyNode->GetFirstChild(getter_AddRefs(bodyChild)); result = bodyNode->GetFirstChild(getter_AddRefs(bodyChild));
while ((NS_SUCCEEDED(result)) && bodyChild) while ((NS_SUCCEEDED(result)) && bodyChild)
{ {
if (PR_TRUE==IsEditable(bodyChild)) if (PR_TRUE==nsEditor::IsEditable(bodyChild))
{ {
needsBogusContent = PR_FALSE; needsBogusContent = PR_FALSE;
break; break;
@ -599,8 +539,8 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection, nsresult aResul
newPElement = do_QueryInterface(mBogusNode); newPElement = do_QueryInterface(mBogusNode);
if (newPElement) if (newPElement)
{ {
nsAutoString att(kMOZEditorBogusNodeAttr); nsAutoString att(nsEditor::kMOZEditorBogusNodeAttr);
nsAutoString val(kMOZEditorBogusNodeValue); nsAutoString val(nsEditor::kMOZEditorBogusNodeValue);
newPElement->SetAttribute(att, val); newPElement->SetAttribute(att, val);
} }
} }
@ -706,10 +646,10 @@ nsTextEditRules:: DidUndo(nsIDOMSelection *aSelection, nsresult aResult)
element = do_QueryInterface(node); element = do_QueryInterface(node);
if (element) if (element)
{ {
nsAutoString att(kMOZEditorBogusNodeAttr); nsAutoString att(nsEditor::kMOZEditorBogusNodeAttr);
nsAutoString val; nsAutoString val;
(void)element->GetAttribute(att, val); (void)element->GetAttribute(att, val);
if (val.Equals(kMOZEditorBogusNodeValue)) { if (val.Equals(nsEditor::kMOZEditorBogusNodeValue)) {
mBogusNode = do_QueryInterface(element); mBogusNode = do_QueryInterface(element);
} }
} }
@ -752,10 +692,10 @@ nsTextEditRules::DidRedo(nsIDOMSelection *aSelection, nsresult aResult)
element = do_QueryInterface(node); element = do_QueryInterface(node);
if (element) if (element)
{ {
nsAutoString att(kMOZEditorBogusNodeAttr); nsAutoString att(nsEditor::kMOZEditorBogusNodeAttr);
nsAutoString val; nsAutoString val;
(void)element->GetAttribute(att, val); (void)element->GetAttribute(att, val);
if (val.Equals(kMOZEditorBogusNodeValue)) { if (val.Equals(nsEditor::kMOZEditorBogusNodeValue)) {
mBogusNode = do_QueryInterface(element); mBogusNode = do_QueryInterface(element);
} }
} }

Просмотреть файл

@ -85,8 +85,6 @@ protected:
nsresult DidRedo(nsIDOMSelection *aSelection, nsresult aResult); nsresult DidRedo(nsIDOMSelection *aSelection, nsresult aResult);
// helper functions // helper functions
static PRBool NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag);
static PRBool IsEditable(nsIDOMNode *aNode);
/** insert aNode into a new style node of type aTag. /** insert aNode into a new style node of type aTag.
* aSelection is optional. If provided, aSelection is set to (aNode, 0) * aSelection is optional. If provided, aSelection is set to (aNode, 0)

Просмотреть файл

@ -226,9 +226,9 @@ public:
* @param aOffset the offset of aExistingRightNode's content|children to do the split at * @param aOffset the offset of aExistingRightNode's content|children to do the split at
* @param aNewLeftNode [OUT] the new node resulting from the split, becomes aExistingRightNode's previous sibling. * @param aNewLeftNode [OUT] the new node resulting from the split, becomes aExistingRightNode's previous sibling.
*/ */
NS_IMETHOD SplitNode(nsIDOMNode * aExistingRightNode, NS_IMETHOD SplitNode(nsIDOMNode *aExistingRightNode,
PRInt32 aOffset, PRInt32 aOffset,
nsIDOMNode ** aNewLeftNode)=0; nsIDOMNode **aNewLeftNode)=0;
/** /**
* JoinNodes() takes 2 nodes and merge their content|children. * JoinNodes() takes 2 nodes and merge their content|children.
@ -333,29 +333,28 @@ public:
* What if no text is selected? * What if no text is selected?
* What about mixed selections? * What about mixed selections?
* What are the clipboard formats? * What are the clipboard formats?
*/ */
NS_IMETHOD Cut()=0; NS_IMETHOD Cut()=0;
/** copy the currently selected text, putting it into the OS clipboard /** copy the currently selected text, putting it into the OS clipboard
* What if no text is selected? * What if no text is selected?
* What about mixed selections? * What about mixed selections?
* What are the clipboard formats? * What are the clipboard formats?
*/ */
NS_IMETHOD Copy()=0; NS_IMETHOD Copy()=0;
/** paste the text in the OS clipboard at the cursor position, replacing /** paste the text in the OS clipboard at the cursor position, replacing
* the selected text (if any) * the selected text (if any)
*/ */
NS_IMETHOD Paste()=0; NS_IMETHOD Paste()=0;
/** add an EditActionListener to the editors list of listeners. /** add an EditActionListener to the editors list of listeners. */
*/
NS_IMETHOD AddEditActionListener(nsIEditActionListener *aListener)=0; NS_IMETHOD AddEditActionListener(nsIEditActionListener *aListener)=0;
/** Remove an EditActionListener from the editor's list of listeners. /** Remove an EditActionListener from the editor's list of listeners. */
*/
NS_IMETHOD RemoveEditActionListener(nsIEditActionListener *aListener)=0; NS_IMETHOD RemoveEditActionListener(nsIEditActionListener *aListener)=0;
/** Dumps a text representation of the content tree to standard out */
NS_IMETHOD DebugDumpContent() const =0; NS_IMETHOD DebugDumpContent() const =0;
}; };

Просмотреть файл

@ -123,11 +123,13 @@ public:
*/ */
NS_IMETHOD ReplaceBlockParent(nsString& aParentTag)=0; NS_IMETHOD ReplaceBlockParent(nsString& aParentTag)=0;
/** remove the paragraph style from the selection */
NS_IMETHOD RemoveParagraphStyle()=0;
/** remove block parent of type aTagToRemove from the selection. /** remove block parent of type aTagToRemove from the selection.
* if aTagToRemove is null, the nearest enclosing block that * if aTagToRemove is null, the nearest enclosing block that
* is <B>not</B> a sub-document is removed. * is <B>not</B> a root is removed.
*/ */
NS_IMETHOD RemoveBlockParent()=0;
NS_IMETHOD RemoveParent(const nsString &aParentTag)=0; NS_IMETHOD RemoveParent(const nsString &aParentTag)=0;
NS_IMETHOD InsertLink(nsString& aURL)=0; NS_IMETHOD InsertLink(nsString& aURL)=0;

Просмотреть файл

@ -27,7 +27,6 @@
#include "nsIEditor.h" #include "nsIEditor.h"
#include "nscore.h" #include "nscore.h"
class nsIEditorCallback;
class nsISupportsArray; class nsISupportsArray;
class nsIAtom; class nsIAtom;
class nsIOutputStream; class nsIOutputStream;