From 061b766061f55d41e269e4481938688143fba547 Mon Sep 17 00:00:00 2001 From: "buster%netscape.com" Date: Wed, 17 Feb 1999 19:42:29 +0000 Subject: [PATCH] Highlights: updated to new nsCOMPtr usage nsTextEditor::InsertBreak() implemented splits the text node at the caret (deletes any extended selection to force a collapsed selection.) inserts a
which I assume we'll convert to a CR when we write to a text stream. undo and redo work, except for the bug noted below More stuff: interface cleanup strategic debugging code added delete selection txn sets the collapses the selection...this is just a placeholder, but I needed it for undo/redo of InsertBreak. join and split now work for text nodes as well as interior nodes --- editor/base/CreateElementTxn.cpp | 7 + editor/base/DeleteRangeTxn.cpp | 40 ++++- editor/base/DeleteRangeTxn.h | 6 +- editor/base/JoinElementTxn.cpp | 19 +- editor/base/SplitElementTxn.cpp | 32 +++- editor/base/nsEditFactory.cpp | 2 +- editor/base/nsEditor.cpp | 192 +++++++++++++++------ editor/base/nsEditor.h | 20 ++- editor/base/nsTextEditor.cpp | 77 ++++++++- editor/base/nsTextEditor.h | 5 + editor/libeditor/base/CreateElementTxn.cpp | 7 + editor/libeditor/base/DeleteRangeTxn.cpp | 40 ++++- editor/libeditor/base/DeleteRangeTxn.h | 6 +- editor/libeditor/base/JoinElementTxn.cpp | 19 +- editor/libeditor/base/SplitElementTxn.cpp | 32 +++- editor/libeditor/base/nsEditor.cpp | 192 +++++++++++++++------ editor/libeditor/base/nsEditor.h | 20 ++- editor/public/nsIEditor.h | 13 +- 18 files changed, 589 insertions(+), 140 deletions(-) diff --git a/editor/base/CreateElementTxn.cpp b/editor/base/CreateElementTxn.cpp index db9192ecfaa..b5abd3b00a0 100644 --- a/editor/base/CreateElementTxn.cpp +++ b/editor/base/CreateElementTxn.cpp @@ -37,6 +37,13 @@ nsresult CreateElementTxn::Init(nsIDOMDocument *aDoc, mOffsetInParent = aOffsetInParent; mNewNode = nsnull; mRefNode = nsnull; +#ifdef NS_DEBUG + { + nsCOMPtr testChildNodes; + nsresult testResult = mParent->GetChildNodes(getter_AddRefs(testChildNodes)); + NS_ASSERTION(testChildNodes, "bad parent type, can't have children."); + } +#endif return NS_OK; } else diff --git a/editor/base/DeleteRangeTxn.cpp b/editor/base/DeleteRangeTxn.cpp index 3bb151247c4..9ca43916b83 100644 --- a/editor/base/DeleteRangeTxn.cpp +++ b/editor/base/DeleteRangeTxn.cpp @@ -20,6 +20,7 @@ #include "nsIDOMRange.h" #include "nsIDOMCharacterData.h" #include "nsIDOMNodeList.h" +#include "nsIDOMSelection.h" #include "DeleteTextTxn.h" #include "DeleteElementTxn.h" #include "TransactionFactory.h" @@ -44,10 +45,11 @@ DeleteRangeTxn::DeleteRangeTxn() { } -nsresult DeleteRangeTxn::Init(nsIDOMRange *aRange) +nsresult DeleteRangeTxn::Init(nsIEditor *aEditor, nsIDOMRange *aRange) { - if (nsnull!=aRange) + if (aEditor && aRange) { + mEditor = aEditor; nsresult result = aRange->GetStartParent(getter_AddRefs(mStartParent)); NS_ASSERTION((NS_SUCCEEDED(result)), "GetStartParent failed."); result = aRange->GetEndParent(getter_AddRefs(mEndParent)); @@ -60,6 +62,7 @@ nsresult DeleteRangeTxn::Init(nsIDOMRange *aRange) NS_ASSERTION((NS_SUCCEEDED(result)), "GetCommonParent failed."); #ifdef NS_DEBUG + { PRUint32 count; nsCOMPtr textNode; textNode = do_QueryInterface(mStartParent, &result); @@ -88,6 +91,7 @@ nsresult DeleteRangeTxn::Init(nsIDOMRange *aRange) if (gNoisy) printf ("DeleteRange: %d of %p to %d of %p\n", mStartOffset, (void *)mStartParent, mEndOffset, (void *)mEndParent); + } #endif return result; } @@ -129,8 +133,18 @@ nsresult DeleteRangeTxn::Do(void) } // if we've successfully built this aggregate transaction, then do it. - if (NS_SUCCEEDED(result)) + if (NS_SUCCEEDED(result)) { result = EditAggregateTxn::Do(); + } + + if (NS_SUCCEEDED(result)) { + // set the resulting selection + nsCOMPtr selection; + result = mEditor->GetSelection(getter_AddRefs(selection)); + if (NS_SUCCEEDED(result)) { + result = selection->Collapse(mStartParent, mStartOffset); + } + } return result; } @@ -141,6 +155,16 @@ nsresult DeleteRangeTxn::Undo(void) return NS_ERROR_NULL_POINTER; nsresult result = EditAggregateTxn::Undo(); + + if (NS_SUCCEEDED(result)) { + // set the resulting selection + nsCOMPtr selection; + result = mEditor->GetSelection(getter_AddRefs(selection)); + if (NS_SUCCEEDED(result)) { + result = selection->Collapse(mStartParent, mStartOffset); + } + } + return result; } @@ -150,6 +174,16 @@ nsresult DeleteRangeTxn::Redo(void) return NS_ERROR_NULL_POINTER; nsresult result = EditAggregateTxn::Redo(); + + if (NS_SUCCEEDED(result)) { + // set the resulting selection + nsCOMPtr selection; + result = mEditor->GetSelection(getter_AddRefs(selection)); + if (NS_SUCCEEDED(result)) { + result = selection->Collapse(mStartParent, mStartOffset); + } + } + return result; } diff --git a/editor/base/DeleteRangeTxn.h b/editor/base/DeleteRangeTxn.h index 620310f258b..2b45a767c17 100644 --- a/editor/base/DeleteRangeTxn.h +++ b/editor/base/DeleteRangeTxn.h @@ -41,9 +41,10 @@ class DeleteRangeTxn : public EditAggregateTxn public: /** initialize the transaction. + * @param aEditor the object providing basic editing operations * @param aRange the range to delete */ - virtual nsresult Init(nsIDOMRange *aRange); + virtual nsresult Init(nsIEditor *aEditor, nsIDOMRange *aRange); private: DeleteRangeTxn(); @@ -100,6 +101,9 @@ protected: /** p2 offset */ PRInt32 mEndOffset; + /** the editor for this transaction */ + nsCOMPtr mEditor; + friend class TransactionFactory; }; diff --git a/editor/base/JoinElementTxn.cpp b/editor/base/JoinElementTxn.cpp index c075da6b2ab..1d3a5f3d706 100644 --- a/editor/base/JoinElementTxn.cpp +++ b/editor/base/JoinElementTxn.cpp @@ -18,6 +18,9 @@ #include "JoinElementTxn.h" #include "nsIDOMNodeList.h" +#include "nsIEditorSupport.h" + +static NS_DEFINE_IID(kIEditorSupportIID, NS_IEDITORSUPPORT_IID); JoinElementTxn::JoinElementTxn() @@ -64,6 +67,12 @@ nsresult JoinElementTxn::Do(void) { childNodes->GetLength(&mOffset); } + //XXX: WRONG! needs commented code below +/* + result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); + if (NS_SUCCEEDED(result) && editor) { + result = editor->JoinNodesImpl(mLeftNode, mRightNode, mParent, PR_FALSE); +*/ result = mEditor->JoinNodes(mLeftNode, mRightNode, mParent, PR_FALSE); } } @@ -75,7 +84,15 @@ nsresult JoinElementTxn::Do(void) nsresult JoinElementTxn::Undo(void) { - nsresult result = mEditor->SplitNode(mRightNode, mOffset, mLeftNode, mParent); + nsresult result; + nsCOMPtr editor; + result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); + if (NS_SUCCEEDED(result) && editor) { + result = editor->SplitNodeImpl(mRightNode, mOffset, mLeftNode, mParent); + } + else { + result = NS_ERROR_NOT_IMPLEMENTED; + } return result; } diff --git a/editor/base/SplitElementTxn.cpp b/editor/base/SplitElementTxn.cpp index d97fe6ceaa2..387d518b29d 100644 --- a/editor/base/SplitElementTxn.cpp +++ b/editor/base/SplitElementTxn.cpp @@ -19,6 +19,9 @@ #include "SplitElementTxn.h" #include "nsIDOMNode.h" #include "nsIDOMElement.h" +#include "nsIEditorSupport.h" + +static NS_DEFINE_IID(kIEditorSupportIID, NS_IEDITORSUPPORT_IID); // note that aEditor is not refcounted SplitElementTxn::SplitElementTxn() @@ -53,7 +56,14 @@ nsresult SplitElementTxn::Do(void) // insert the new node if ((NS_SUCCEEDED(result)) && (mParent)) { - result = mEditor->SplitNode(mExistingRightNode, mOffset, mNewLeftNode, mParent); + nsCOMPtr editor; + result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); + if (NS_SUCCEEDED(result) && editor) { + result = editor->SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent); + } + else { + result = NS_ERROR_NOT_IMPLEMENTED; + } } } return result; @@ -62,13 +72,29 @@ nsresult SplitElementTxn::Do(void) nsresult SplitElementTxn::Undo(void) { // this assumes Do inserted the new node in front of the prior existing node - nsresult result = mEditor->JoinNodes(mExistingRightNode, mNewLeftNode, mParent, PR_FALSE); + nsresult result; + nsCOMPtr editor; + result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); + if (NS_SUCCEEDED(result) && editor) { + result = editor->JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent, PR_FALSE); + } + else { + result = NS_ERROR_NOT_IMPLEMENTED; + } return result; } nsresult SplitElementTxn::Redo(void) { - nsresult result = mEditor->SplitNode(mExistingRightNode, mOffset, mNewLeftNode, mParent); + nsresult result; + nsCOMPtr editor; + result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); + if (NS_SUCCEEDED(result) && editor) { + result = editor->SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent); + } + else { + result = NS_ERROR_NOT_IMPLEMENTED; + } return result; } diff --git a/editor/base/nsEditFactory.cpp b/editor/base/nsEditFactory.cpp index d5a80afca53..e838eec7a17 100644 --- a/editor/base/nsEditFactory.cpp +++ b/editor/base/nsEditFactory.cpp @@ -86,7 +86,7 @@ nsEditFactory::CreateInstance(nsISupports *aOuter, REFNSIID aIID, void **aResult if (mCID.Equals(kEditorCID)) - obj = (nsISupports *)new nsEditor(); + obj = (nsISupports *)(nsIEditor*)new nsEditor(); //more class ids to support. here diff --git a/editor/base/nsEditor.cpp b/editor/base/nsEditor.cpp index e1f7c9a26b2..bfe1d249bdc 100644 --- a/editor/base/nsEditor.cpp +++ b/editor/base/nsEditor.cpp @@ -67,6 +67,7 @@ static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID); static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID); static NS_DEFINE_IID(kIEditFactoryIID, NS_IEDITORFACTORY_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(kEditorCID, NS_EDITOR_CID); static NS_DEFINE_CID(kTextEditorCID, NS_TEXTEDITOR_CID); @@ -211,7 +212,9 @@ nsEditor::QueryInterface(REFNSIID aIID, void** aInstancePtr) return NS_ERROR_NULL_POINTER; } if (aIID.Equals(kISupportsIID)) { - *aInstancePtr = (void*)(nsISupports*)this; + nsIEditor *tmp = this; + nsISupports *tmp2 = tmp; + *aInstancePtr = (void*)tmp2; NS_ADDREF_THIS(); return NS_OK; } @@ -220,6 +223,11 @@ nsEditor::QueryInterface(REFNSIID aIID, void** aInstancePtr) NS_ADDREF_THIS(); return NS_OK; } + if (aIID.Equals(kIEditorSupportIID)) { + *aInstancePtr = (void*)(nsIEditorSupport*)this; + NS_ADDREF_THIS(); + return NS_OK; + } return NS_NOINTERFACE; } @@ -235,7 +243,15 @@ nsEditor::GetDocument(nsIDOMDocument **aDoc) return mDoc->QueryInterface(kIDOMDocumentIID, (void **)aDoc); } - +nsresult +nsEditor::GetSelection(nsIDOMSelection **aSelection) +{ + if (!aSelection) + return NS_ERROR_NULL_POINTER; + *aSelection = nsnull; + nsresult result = mPresShell->GetSelection(aSelection); // does an addref + return result; +} nsresult nsEditor::Init(nsIDOMDocument *aDoc, nsIPresShell* aPresShell) @@ -383,9 +399,9 @@ nsEditor::GetAttributeValue(nsIDOMElement *aElement, nsresult result=NS_OK; if (nsnull!=aElement) { - nsIDOMAttr* attNode=nsnull; - result = aElement->GetAttributeNode(aAttribute, &attNode); - if ((NS_SUCCEEDED(result)) && (nsnull!=attNode)) + nsCOMPtr attNode; + result = aElement->GetAttributeNode(aAttribute, getter_AddRefs(attNode)); + if ((NS_SUCCEEDED(result)) && attNode) { attNode->GetSpecified(&aResultIsSet); attNode->GetValue(aResultValue); @@ -955,7 +971,7 @@ nsresult nsEditor::CreateTxnForDeleteSelection(nsIEditor::Direction aDir, result = TransactionFactory::GetNewTransaction(kDeleteRangeTxnIID, (EditTxn **)&txn); if ((NS_SUCCEEDED(result)) && (nsnull!=txn)) { - txn->Init(range); + txn->Init(this, range); (*aTxn)->AppendChild(txn); } else @@ -1224,6 +1240,18 @@ nsEditor::GetLeftmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode) return result; } +nsresult +nsEditor::SplitNode(nsIDOMNode * aNode, + PRInt32 aOffset) +{ + SplitElementTxn *txn; + nsresult result = CreateTxnForSplitNode(aNode, aOffset, &txn); + if (NS_SUCCEEDED(result)) { + result = Do(txn); + } + return result; +} + nsresult nsEditor::CreateTxnForSplitNode(nsIDOMNode *aNode, PRUint32 aOffset, SplitElementTxn **aTxn) @@ -1239,6 +1267,20 @@ nsresult nsEditor::CreateTxnForSplitNode(nsIDOMNode *aNode, return result; } +nsresult +nsEditor::JoinNodes(nsIDOMNode * aNodeToKeep, + nsIDOMNode * aNodeToJoin, + nsIDOMNode * aParent, + PRBool aNodeToKeepIsFirst) +{ + JoinElementTxn *txn; + nsresult result = CreateTxnForJoinNode(aNodeToKeep, aNodeToJoin, &txn); + if (NS_SUCCEEDED(result)) { + result = Do(txn); + } + return result; +} + nsresult nsEditor::CreateTxnForJoinNode(nsIDOMNode *aLeftNode, nsIDOMNode *aRightNode, JoinElementTxn **aTxn) @@ -1255,10 +1297,10 @@ nsresult nsEditor::CreateTxnForJoinNode(nsIDOMNode *aLeftNode, } nsresult -nsEditor::SplitNode(nsIDOMNode * aExistingRightNode, - PRInt32 aOffset, - nsIDOMNode* aNewLeftNode, - nsIDOMNode* aParent) +nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode, + PRInt32 aOffset, + nsIDOMNode* aNewLeftNode, + nsIDOMNode* aParent) { nsresult result; NS_ASSERTION(((nsnull!=aExistingRightNode) && @@ -1278,25 +1320,40 @@ nsEditor::SplitNode(nsIDOMNode * aExistingRightNode, // move all the children whose index is < aOffset to aNewLeftNode if (0<=aOffset) // don't bother unless we're going to move at least one child { - nsCOMPtr childNodes; - result = aExistingRightNode->GetChildNodes(getter_AddRefs(childNodes)); - if ((NS_SUCCEEDED(result)) && (childNodes)) + // if it's a text node, just shuffle around some text + nsCOMPtr rightNodeAsText(aExistingRightNode); + nsCOMPtr leftNodeAsText(aNewLeftNode); + if (leftNodeAsText && rightNodeAsText) { - PRInt32 i=0; - for ( ; ((NS_SUCCEEDED(result)) && (iSubstringData(0, aOffset, leftText); + rightNodeAsText->DeleteData(0, aOffset); + // fix left node + leftNodeAsText->SetData(leftText); + } + else + { // otherwise it's an interior node, so shuffle around the children + nsCOMPtr childNodes; + result = aExistingRightNode->GetChildNodes(getter_AddRefs(childNodes)); + if ((NS_SUCCEEDED(result)) && (childNodes)) { - nsCOMPtr childNode; - result = childNodes->Item(i, getter_AddRefs(childNode)); - if ((NS_SUCCEEDED(result)) && (childNode)) + PRInt32 i=0; + for ( ; ((NS_SUCCEEDED(result)) && (iRemoveChild(childNode, getter_AddRefs(resultNode)); - if (NS_SUCCEEDED(result)) + nsCOMPtr childNode; + result = childNodes->Item(i, getter_AddRefs(childNode)); + if ((NS_SUCCEEDED(result)) && (childNode)) { - result = aNewLeftNode->AppendChild(childNode, getter_AddRefs(resultNode)); + result = aExistingRightNode->RemoveChild(childNode, getter_AddRefs(resultNode)); + if (NS_SUCCEEDED(result)) + { + result = aNewLeftNode->AppendChild(childNode, getter_AddRefs(resultNode)); + } } } - } - } + } + } } } } @@ -1307,10 +1364,10 @@ nsEditor::SplitNode(nsIDOMNode * aExistingRightNode, } nsresult -nsEditor::JoinNodes(nsIDOMNode * aNodeToKeep, - nsIDOMNode * aNodeToJoin, - nsIDOMNode * aParent, - PRBool aNodeToKeepIsFirst) +nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep, + nsIDOMNode * aNodeToJoin, + nsIDOMNode * aParent, + PRBool aNodeToKeepIsFirst) { nsresult result; NS_ASSERTION(((nsnull!=aNodeToKeep) && @@ -1321,41 +1378,68 @@ nsEditor::JoinNodes(nsIDOMNode * aNodeToKeep, (nsnull!=aNodeToJoin) && (nsnull!=aParent)) { - nsCOMPtr childNodes; - result = aNodeToJoin->GetChildNodes(getter_AddRefs(childNodes)); - if ((NS_SUCCEEDED(result)) && (childNodes)) + // if it's a text node, just shuffle around some text + nsCOMPtr keepNodeAsText(aNodeToKeep); + nsCOMPtr joinNodeAsText(aNodeToJoin); + if (keepNodeAsText && joinNodeAsText) { - PRUint32 i; - PRUint32 childCount=0; - childNodes->GetLength(&childCount); - nsCOMPtr firstNode; //only used if aNodeToKeepIsFirst is false - if (PR_FALSE==aNodeToKeepIsFirst) - { // remember the first child in aNodeToKeep, we'll insert all the children of aNodeToJoin in front of it - result = aNodeToKeep->GetFirstChild(getter_AddRefs(firstNode)); - // GetFirstChild returns nsnull firstNode if aNodeToKeep has no children, that's ok. - } - nsCOMPtr resultNode; - for (i=0; ((NS_SUCCEEDED(result)) && (i childNode; - result = childNodes->Item(i, getter_AddRefs(childNode)); - if ((NS_SUCCEEDED(result)) && (childNode)) + keepNodeAsText->GetData(leftText); + joinNodeAsText->GetData(rightText); + } + else + { + keepNodeAsText->GetData(rightText); + joinNodeAsText->GetData(leftText); + } + leftText += rightText; + keepNodeAsText->SetData(leftText); + } + else + { // otherwise it's an interior node, so shuffle around the children + nsCOMPtr childNodes; + result = aNodeToJoin->GetChildNodes(getter_AddRefs(childNodes)); + if ((NS_SUCCEEDED(result)) && (childNodes)) + { + PRUint32 i; + PRUint32 childCount=0; + childNodes->GetLength(&childCount); + nsCOMPtr firstNode; //only used if aNodeToKeepIsFirst is false + if (PR_FALSE==aNodeToKeepIsFirst) + { // remember the first child in aNodeToKeep, we'll insert all the children of aNodeToJoin in front of it + result = aNodeToKeep->GetFirstChild(getter_AddRefs(firstNode)); + // GetFirstChild returns nsnull firstNode if aNodeToKeep has no children, that's ok. + } + nsCOMPtr resultNode; + for (i=0; ((NS_SUCCEEDED(result)) && (iAppendChild(childNode, getter_AddRefs(resultNode)); - } - else - { // prepend children of aNodeToJoin - result = aNodeToKeep->InsertBefore(childNode, firstNode, getter_AddRefs(resultNode)); + nsCOMPtr childNode; + result = childNodes->Item(i, getter_AddRefs(childNode)); + if ((NS_SUCCEEDED(result)) && (childNode)) + { + if (PR_TRUE==aNodeToKeepIsFirst) + { // append children of aNodeToJoin + result = aNodeToKeep->AppendChild(childNode, getter_AddRefs(resultNode)); + } + else + { // prepend children of aNodeToJoin + result = aNodeToKeep->InsertBefore(childNode, firstNode, getter_AddRefs(resultNode)); + } } } } - if (NS_SUCCEEDED(result)) - { // delete the extra node - result = aParent->RemoveChild(aNodeToJoin, getter_AddRefs(resultNode)); + else if (!childNodes) { + result = NS_ERROR_NULL_POINTER; } } + if (NS_SUCCEEDED(result)) + { // delete the extra node + nsCOMPtr resultNode; + result = aParent->RemoveChild(aNodeToJoin, getter_AddRefs(resultNode)); + } } else result = NS_ERROR_INVALID_ARG; diff --git a/editor/base/nsEditor.h b/editor/base/nsEditor.h index a640705777d..045c7ab1c60 100644 --- a/editor/base/nsEditor.h +++ b/editor/base/nsEditor.h @@ -21,6 +21,7 @@ #include "prmon.h" #include "nsIEditor.h" +#include "nsIEditorSupport.h" #include "nsIContextLoader.h" #include "nsIDOMDocument.h" #include "nsIDOMEventListener.h" @@ -28,7 +29,6 @@ #include "nsITransactionManager.h" #include "TransactionFactory.h" #include "nsRepository.h" -//#include "nsISelection.h" class nsIDOMCharacterData; class nsIDOMRange; @@ -72,7 +72,7 @@ inline Property::Property(nsIAtom *aPropName, nsIAtom *aValue, PRBool aAppliesTo * 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. */ -class nsEditor : public nsIEditor +class nsEditor : public nsIEditor, public nsIEditorSupport { private: nsIPresShell *mPresShell; @@ -104,6 +104,8 @@ public: virtual nsresult GetDocument(nsIDOMDocument **aDoc); + virtual nsresult GetSelection(nsIDOMSelection **aSelection); + virtual nsresult SetProperties(nsVoidArray *aPropList); virtual nsresult GetProperties(nsVoidArray *aPropList); @@ -133,9 +135,7 @@ public: virtual nsresult DeleteSelection(nsIEditor::Direction aDir); virtual nsresult SplitNode(nsIDOMNode * aExistingRightNode, - PRInt32 aOffset, - nsIDOMNode * aNewLeftNode, - nsIDOMNode * aParent); + PRInt32 aOffset); virtual nsresult JoinNodes(nsIDOMNode * aNodeToKeep, nsIDOMNode * aNodeToJoin, @@ -232,10 +232,20 @@ protected: PRUint32 aOffset, SplitElementTxn **aTxn); + virtual nsresult SplitNodeImpl(nsIDOMNode * aExistingRightNode, + PRInt32 aOffset, + nsIDOMNode * aNewLeftNode, + nsIDOMNode * aParent); + virtual nsresult CreateTxnForJoinNode(nsIDOMNode *aLeftNode, nsIDOMNode *aRightNode, JoinElementTxn **aTxn); + virtual nsresult JoinNodesImpl(nsIDOMNode * aNodeToKeep, + nsIDOMNode * aNodeToJoin, + nsIDOMNode * aParent, + PRBool aNodeToKeepIsFirst); + #if 0 nsresult CreateTxnToHandleEnterKey(EditAggregateTxn **aTxn); #endif diff --git a/editor/base/nsTextEditor.cpp b/editor/base/nsTextEditor.cpp index 0fbc6d920bd..51ba8f08de1 100644 --- a/editor/base/nsTextEditor.cpp +++ b/editor/base/nsTextEditor.cpp @@ -22,8 +22,12 @@ #include "nsIDOMEventReceiver.h" #include "nsIDOMKeyListener.h" #include "nsIDOMMouseListener.h" +#include "nsIDOMSelection.h" +#include "nsIDOMNodeList.h" #include "nsEditorCID.h" +#include "CreateElementTxn.h" + #include "nsRepository.h" #include "nsIServiceManager.h" @@ -171,7 +175,42 @@ nsresult nsTextEditor::InsertBreak(PRBool aCtrlKey) nsresult result=NS_ERROR_NOT_INITIALIZED; if (mEditor) { - result = NS_ERROR_NOT_IMPLEMENTED; + PRBool beganTransaction = PR_FALSE; + nsCOMPtr selection; + result = mEditor->GetSelection(getter_AddRefs(selection)); + if ((NS_SUCCEEDED(result)) && selection) + { + beganTransaction = PR_TRUE; + result = mEditor->BeginTransaction(); + PRBool collapsed; + result = selection->IsCollapsed(&collapsed); + if (NS_SUCCEEDED(result) && !collapsed) + { + result = mEditor->DeleteSelection(nsIEditor::eLTR); + // get the new selection + result = mEditor->GetSelection(getter_AddRefs(selection)); +#ifdef NS_DEBUG + PRBool testCollapsed; + result = selection->IsCollapsed(&testCollapsed); + NS_ASSERTION(PR_TRUE==testCollapsed, "selection not reset after deletion"); +#endif + } + // split the text node + nsCOMPtr node; + PRInt32 offset; + result = selection->GetAnchorNodeAndOffset(getter_AddRefs(node), &offset); + nsCOMPtr parentNode; + result = node->GetParentNode(getter_AddRefs(parentNode)); + result = mEditor->SplitNode(node, offset); + // now get the node's offset in it's parent, and insert the new BR there + result = GetChildOffset(node, parentNode, offset); + nsAutoString tag("BR"); + result = mEditor->CreateNode(tag, parentNode, offset); + selection->Collapse(parentNode, offset); + } + if (PR_TRUE==beganTransaction) { + result = mEditor->EndTransaction(); + } } return result; } @@ -389,3 +428,39 @@ nsTextEditor::QueryInterface(REFNSIID aIID, void** aInstancePtr) } return NS_NOINTERFACE; } + + +// utility methods + +nsresult nsTextEditor::GetChildOffset(nsIDOMNode *aChild, nsIDOMNode *aParent, PRInt32 &aOffset) +{ + NS_ASSERTION((aChild && aParent), "bad args"); + nsresult result = NS_ERROR_NULL_POINTER; + if (aChild && aParent) + { + nsCOMPtr childNodes; + result = aParent->GetChildNodes(getter_AddRefs(childNodes)); + if ((NS_SUCCEEDED(result)) && (childNodes)) + { + PRInt32 i=0; + for ( ; NS_SUCCEEDED(result); i++) + { + nsCOMPtr childNode; + result = childNodes->Item(i, getter_AddRefs(childNode)); + if ((NS_SUCCEEDED(result)) && (childNode)) + { + if (childNode==aChild) + { + aOffset = i; + break; + } + } + else if (!childNode) + result = NS_ERROR_NULL_POINTER; + } + } + else if (!childNodes) + result = NS_ERROR_NULL_POINTER; + } + return result; +} diff --git a/editor/base/nsTextEditor.h b/editor/base/nsTextEditor.h index d9ddd96617b..7cc8bb7208b 100644 --- a/editor/base/nsTextEditor.h +++ b/editor/base/nsTextEditor.h @@ -77,6 +77,11 @@ public: virtual nsresult OutputText(nsIOutputStream *aOutputStream); virtual nsresult OutputHTML(nsIOutputStream *aOutputStream); +// Utility methods +protected: + virtual nsresult GetChildOffset(nsIDOMNode *aChild, nsIDOMNode *aParent, PRInt32 &aOffset); + +// Data members protected: nsCOMPtr mEditor; nsCOMPtr mKeyListenerP; diff --git a/editor/libeditor/base/CreateElementTxn.cpp b/editor/libeditor/base/CreateElementTxn.cpp index db9192ecfaa..b5abd3b00a0 100644 --- a/editor/libeditor/base/CreateElementTxn.cpp +++ b/editor/libeditor/base/CreateElementTxn.cpp @@ -37,6 +37,13 @@ nsresult CreateElementTxn::Init(nsIDOMDocument *aDoc, mOffsetInParent = aOffsetInParent; mNewNode = nsnull; mRefNode = nsnull; +#ifdef NS_DEBUG + { + nsCOMPtr testChildNodes; + nsresult testResult = mParent->GetChildNodes(getter_AddRefs(testChildNodes)); + NS_ASSERTION(testChildNodes, "bad parent type, can't have children."); + } +#endif return NS_OK; } else diff --git a/editor/libeditor/base/DeleteRangeTxn.cpp b/editor/libeditor/base/DeleteRangeTxn.cpp index 3bb151247c4..9ca43916b83 100644 --- a/editor/libeditor/base/DeleteRangeTxn.cpp +++ b/editor/libeditor/base/DeleteRangeTxn.cpp @@ -20,6 +20,7 @@ #include "nsIDOMRange.h" #include "nsIDOMCharacterData.h" #include "nsIDOMNodeList.h" +#include "nsIDOMSelection.h" #include "DeleteTextTxn.h" #include "DeleteElementTxn.h" #include "TransactionFactory.h" @@ -44,10 +45,11 @@ DeleteRangeTxn::DeleteRangeTxn() { } -nsresult DeleteRangeTxn::Init(nsIDOMRange *aRange) +nsresult DeleteRangeTxn::Init(nsIEditor *aEditor, nsIDOMRange *aRange) { - if (nsnull!=aRange) + if (aEditor && aRange) { + mEditor = aEditor; nsresult result = aRange->GetStartParent(getter_AddRefs(mStartParent)); NS_ASSERTION((NS_SUCCEEDED(result)), "GetStartParent failed."); result = aRange->GetEndParent(getter_AddRefs(mEndParent)); @@ -60,6 +62,7 @@ nsresult DeleteRangeTxn::Init(nsIDOMRange *aRange) NS_ASSERTION((NS_SUCCEEDED(result)), "GetCommonParent failed."); #ifdef NS_DEBUG + { PRUint32 count; nsCOMPtr textNode; textNode = do_QueryInterface(mStartParent, &result); @@ -88,6 +91,7 @@ nsresult DeleteRangeTxn::Init(nsIDOMRange *aRange) if (gNoisy) printf ("DeleteRange: %d of %p to %d of %p\n", mStartOffset, (void *)mStartParent, mEndOffset, (void *)mEndParent); + } #endif return result; } @@ -129,8 +133,18 @@ nsresult DeleteRangeTxn::Do(void) } // if we've successfully built this aggregate transaction, then do it. - if (NS_SUCCEEDED(result)) + if (NS_SUCCEEDED(result)) { result = EditAggregateTxn::Do(); + } + + if (NS_SUCCEEDED(result)) { + // set the resulting selection + nsCOMPtr selection; + result = mEditor->GetSelection(getter_AddRefs(selection)); + if (NS_SUCCEEDED(result)) { + result = selection->Collapse(mStartParent, mStartOffset); + } + } return result; } @@ -141,6 +155,16 @@ nsresult DeleteRangeTxn::Undo(void) return NS_ERROR_NULL_POINTER; nsresult result = EditAggregateTxn::Undo(); + + if (NS_SUCCEEDED(result)) { + // set the resulting selection + nsCOMPtr selection; + result = mEditor->GetSelection(getter_AddRefs(selection)); + if (NS_SUCCEEDED(result)) { + result = selection->Collapse(mStartParent, mStartOffset); + } + } + return result; } @@ -150,6 +174,16 @@ nsresult DeleteRangeTxn::Redo(void) return NS_ERROR_NULL_POINTER; nsresult result = EditAggregateTxn::Redo(); + + if (NS_SUCCEEDED(result)) { + // set the resulting selection + nsCOMPtr selection; + result = mEditor->GetSelection(getter_AddRefs(selection)); + if (NS_SUCCEEDED(result)) { + result = selection->Collapse(mStartParent, mStartOffset); + } + } + return result; } diff --git a/editor/libeditor/base/DeleteRangeTxn.h b/editor/libeditor/base/DeleteRangeTxn.h index 620310f258b..2b45a767c17 100644 --- a/editor/libeditor/base/DeleteRangeTxn.h +++ b/editor/libeditor/base/DeleteRangeTxn.h @@ -41,9 +41,10 @@ class DeleteRangeTxn : public EditAggregateTxn public: /** initialize the transaction. + * @param aEditor the object providing basic editing operations * @param aRange the range to delete */ - virtual nsresult Init(nsIDOMRange *aRange); + virtual nsresult Init(nsIEditor *aEditor, nsIDOMRange *aRange); private: DeleteRangeTxn(); @@ -100,6 +101,9 @@ protected: /** p2 offset */ PRInt32 mEndOffset; + /** the editor for this transaction */ + nsCOMPtr mEditor; + friend class TransactionFactory; }; diff --git a/editor/libeditor/base/JoinElementTxn.cpp b/editor/libeditor/base/JoinElementTxn.cpp index c075da6b2ab..1d3a5f3d706 100644 --- a/editor/libeditor/base/JoinElementTxn.cpp +++ b/editor/libeditor/base/JoinElementTxn.cpp @@ -18,6 +18,9 @@ #include "JoinElementTxn.h" #include "nsIDOMNodeList.h" +#include "nsIEditorSupport.h" + +static NS_DEFINE_IID(kIEditorSupportIID, NS_IEDITORSUPPORT_IID); JoinElementTxn::JoinElementTxn() @@ -64,6 +67,12 @@ nsresult JoinElementTxn::Do(void) { childNodes->GetLength(&mOffset); } + //XXX: WRONG! needs commented code below +/* + result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); + if (NS_SUCCEEDED(result) && editor) { + result = editor->JoinNodesImpl(mLeftNode, mRightNode, mParent, PR_FALSE); +*/ result = mEditor->JoinNodes(mLeftNode, mRightNode, mParent, PR_FALSE); } } @@ -75,7 +84,15 @@ nsresult JoinElementTxn::Do(void) nsresult JoinElementTxn::Undo(void) { - nsresult result = mEditor->SplitNode(mRightNode, mOffset, mLeftNode, mParent); + nsresult result; + nsCOMPtr editor; + result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); + if (NS_SUCCEEDED(result) && editor) { + result = editor->SplitNodeImpl(mRightNode, mOffset, mLeftNode, mParent); + } + else { + result = NS_ERROR_NOT_IMPLEMENTED; + } return result; } diff --git a/editor/libeditor/base/SplitElementTxn.cpp b/editor/libeditor/base/SplitElementTxn.cpp index d97fe6ceaa2..387d518b29d 100644 --- a/editor/libeditor/base/SplitElementTxn.cpp +++ b/editor/libeditor/base/SplitElementTxn.cpp @@ -19,6 +19,9 @@ #include "SplitElementTxn.h" #include "nsIDOMNode.h" #include "nsIDOMElement.h" +#include "nsIEditorSupport.h" + +static NS_DEFINE_IID(kIEditorSupportIID, NS_IEDITORSUPPORT_IID); // note that aEditor is not refcounted SplitElementTxn::SplitElementTxn() @@ -53,7 +56,14 @@ nsresult SplitElementTxn::Do(void) // insert the new node if ((NS_SUCCEEDED(result)) && (mParent)) { - result = mEditor->SplitNode(mExistingRightNode, mOffset, mNewLeftNode, mParent); + nsCOMPtr editor; + result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); + if (NS_SUCCEEDED(result) && editor) { + result = editor->SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent); + } + else { + result = NS_ERROR_NOT_IMPLEMENTED; + } } } return result; @@ -62,13 +72,29 @@ nsresult SplitElementTxn::Do(void) nsresult SplitElementTxn::Undo(void) { // this assumes Do inserted the new node in front of the prior existing node - nsresult result = mEditor->JoinNodes(mExistingRightNode, mNewLeftNode, mParent, PR_FALSE); + nsresult result; + nsCOMPtr editor; + result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); + if (NS_SUCCEEDED(result) && editor) { + result = editor->JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent, PR_FALSE); + } + else { + result = NS_ERROR_NOT_IMPLEMENTED; + } return result; } nsresult SplitElementTxn::Redo(void) { - nsresult result = mEditor->SplitNode(mExistingRightNode, mOffset, mNewLeftNode, mParent); + nsresult result; + nsCOMPtr editor; + result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); + if (NS_SUCCEEDED(result) && editor) { + result = editor->SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent); + } + else { + result = NS_ERROR_NOT_IMPLEMENTED; + } return result; } diff --git a/editor/libeditor/base/nsEditor.cpp b/editor/libeditor/base/nsEditor.cpp index e1f7c9a26b2..bfe1d249bdc 100644 --- a/editor/libeditor/base/nsEditor.cpp +++ b/editor/libeditor/base/nsEditor.cpp @@ -67,6 +67,7 @@ static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID); static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID); static NS_DEFINE_IID(kIEditFactoryIID, NS_IEDITORFACTORY_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(kEditorCID, NS_EDITOR_CID); static NS_DEFINE_CID(kTextEditorCID, NS_TEXTEDITOR_CID); @@ -211,7 +212,9 @@ nsEditor::QueryInterface(REFNSIID aIID, void** aInstancePtr) return NS_ERROR_NULL_POINTER; } if (aIID.Equals(kISupportsIID)) { - *aInstancePtr = (void*)(nsISupports*)this; + nsIEditor *tmp = this; + nsISupports *tmp2 = tmp; + *aInstancePtr = (void*)tmp2; NS_ADDREF_THIS(); return NS_OK; } @@ -220,6 +223,11 @@ nsEditor::QueryInterface(REFNSIID aIID, void** aInstancePtr) NS_ADDREF_THIS(); return NS_OK; } + if (aIID.Equals(kIEditorSupportIID)) { + *aInstancePtr = (void*)(nsIEditorSupport*)this; + NS_ADDREF_THIS(); + return NS_OK; + } return NS_NOINTERFACE; } @@ -235,7 +243,15 @@ nsEditor::GetDocument(nsIDOMDocument **aDoc) return mDoc->QueryInterface(kIDOMDocumentIID, (void **)aDoc); } - +nsresult +nsEditor::GetSelection(nsIDOMSelection **aSelection) +{ + if (!aSelection) + return NS_ERROR_NULL_POINTER; + *aSelection = nsnull; + nsresult result = mPresShell->GetSelection(aSelection); // does an addref + return result; +} nsresult nsEditor::Init(nsIDOMDocument *aDoc, nsIPresShell* aPresShell) @@ -383,9 +399,9 @@ nsEditor::GetAttributeValue(nsIDOMElement *aElement, nsresult result=NS_OK; if (nsnull!=aElement) { - nsIDOMAttr* attNode=nsnull; - result = aElement->GetAttributeNode(aAttribute, &attNode); - if ((NS_SUCCEEDED(result)) && (nsnull!=attNode)) + nsCOMPtr attNode; + result = aElement->GetAttributeNode(aAttribute, getter_AddRefs(attNode)); + if ((NS_SUCCEEDED(result)) && attNode) { attNode->GetSpecified(&aResultIsSet); attNode->GetValue(aResultValue); @@ -955,7 +971,7 @@ nsresult nsEditor::CreateTxnForDeleteSelection(nsIEditor::Direction aDir, result = TransactionFactory::GetNewTransaction(kDeleteRangeTxnIID, (EditTxn **)&txn); if ((NS_SUCCEEDED(result)) && (nsnull!=txn)) { - txn->Init(range); + txn->Init(this, range); (*aTxn)->AppendChild(txn); } else @@ -1224,6 +1240,18 @@ nsEditor::GetLeftmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode) return result; } +nsresult +nsEditor::SplitNode(nsIDOMNode * aNode, + PRInt32 aOffset) +{ + SplitElementTxn *txn; + nsresult result = CreateTxnForSplitNode(aNode, aOffset, &txn); + if (NS_SUCCEEDED(result)) { + result = Do(txn); + } + return result; +} + nsresult nsEditor::CreateTxnForSplitNode(nsIDOMNode *aNode, PRUint32 aOffset, SplitElementTxn **aTxn) @@ -1239,6 +1267,20 @@ nsresult nsEditor::CreateTxnForSplitNode(nsIDOMNode *aNode, return result; } +nsresult +nsEditor::JoinNodes(nsIDOMNode * aNodeToKeep, + nsIDOMNode * aNodeToJoin, + nsIDOMNode * aParent, + PRBool aNodeToKeepIsFirst) +{ + JoinElementTxn *txn; + nsresult result = CreateTxnForJoinNode(aNodeToKeep, aNodeToJoin, &txn); + if (NS_SUCCEEDED(result)) { + result = Do(txn); + } + return result; +} + nsresult nsEditor::CreateTxnForJoinNode(nsIDOMNode *aLeftNode, nsIDOMNode *aRightNode, JoinElementTxn **aTxn) @@ -1255,10 +1297,10 @@ nsresult nsEditor::CreateTxnForJoinNode(nsIDOMNode *aLeftNode, } nsresult -nsEditor::SplitNode(nsIDOMNode * aExistingRightNode, - PRInt32 aOffset, - nsIDOMNode* aNewLeftNode, - nsIDOMNode* aParent) +nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode, + PRInt32 aOffset, + nsIDOMNode* aNewLeftNode, + nsIDOMNode* aParent) { nsresult result; NS_ASSERTION(((nsnull!=aExistingRightNode) && @@ -1278,25 +1320,40 @@ nsEditor::SplitNode(nsIDOMNode * aExistingRightNode, // move all the children whose index is < aOffset to aNewLeftNode if (0<=aOffset) // don't bother unless we're going to move at least one child { - nsCOMPtr childNodes; - result = aExistingRightNode->GetChildNodes(getter_AddRefs(childNodes)); - if ((NS_SUCCEEDED(result)) && (childNodes)) + // if it's a text node, just shuffle around some text + nsCOMPtr rightNodeAsText(aExistingRightNode); + nsCOMPtr leftNodeAsText(aNewLeftNode); + if (leftNodeAsText && rightNodeAsText) { - PRInt32 i=0; - for ( ; ((NS_SUCCEEDED(result)) && (iSubstringData(0, aOffset, leftText); + rightNodeAsText->DeleteData(0, aOffset); + // fix left node + leftNodeAsText->SetData(leftText); + } + else + { // otherwise it's an interior node, so shuffle around the children + nsCOMPtr childNodes; + result = aExistingRightNode->GetChildNodes(getter_AddRefs(childNodes)); + if ((NS_SUCCEEDED(result)) && (childNodes)) { - nsCOMPtr childNode; - result = childNodes->Item(i, getter_AddRefs(childNode)); - if ((NS_SUCCEEDED(result)) && (childNode)) + PRInt32 i=0; + for ( ; ((NS_SUCCEEDED(result)) && (iRemoveChild(childNode, getter_AddRefs(resultNode)); - if (NS_SUCCEEDED(result)) + nsCOMPtr childNode; + result = childNodes->Item(i, getter_AddRefs(childNode)); + if ((NS_SUCCEEDED(result)) && (childNode)) { - result = aNewLeftNode->AppendChild(childNode, getter_AddRefs(resultNode)); + result = aExistingRightNode->RemoveChild(childNode, getter_AddRefs(resultNode)); + if (NS_SUCCEEDED(result)) + { + result = aNewLeftNode->AppendChild(childNode, getter_AddRefs(resultNode)); + } } } - } - } + } + } } } } @@ -1307,10 +1364,10 @@ nsEditor::SplitNode(nsIDOMNode * aExistingRightNode, } nsresult -nsEditor::JoinNodes(nsIDOMNode * aNodeToKeep, - nsIDOMNode * aNodeToJoin, - nsIDOMNode * aParent, - PRBool aNodeToKeepIsFirst) +nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep, + nsIDOMNode * aNodeToJoin, + nsIDOMNode * aParent, + PRBool aNodeToKeepIsFirst) { nsresult result; NS_ASSERTION(((nsnull!=aNodeToKeep) && @@ -1321,41 +1378,68 @@ nsEditor::JoinNodes(nsIDOMNode * aNodeToKeep, (nsnull!=aNodeToJoin) && (nsnull!=aParent)) { - nsCOMPtr childNodes; - result = aNodeToJoin->GetChildNodes(getter_AddRefs(childNodes)); - if ((NS_SUCCEEDED(result)) && (childNodes)) + // if it's a text node, just shuffle around some text + nsCOMPtr keepNodeAsText(aNodeToKeep); + nsCOMPtr joinNodeAsText(aNodeToJoin); + if (keepNodeAsText && joinNodeAsText) { - PRUint32 i; - PRUint32 childCount=0; - childNodes->GetLength(&childCount); - nsCOMPtr firstNode; //only used if aNodeToKeepIsFirst is false - if (PR_FALSE==aNodeToKeepIsFirst) - { // remember the first child in aNodeToKeep, we'll insert all the children of aNodeToJoin in front of it - result = aNodeToKeep->GetFirstChild(getter_AddRefs(firstNode)); - // GetFirstChild returns nsnull firstNode if aNodeToKeep has no children, that's ok. - } - nsCOMPtr resultNode; - for (i=0; ((NS_SUCCEEDED(result)) && (i childNode; - result = childNodes->Item(i, getter_AddRefs(childNode)); - if ((NS_SUCCEEDED(result)) && (childNode)) + keepNodeAsText->GetData(leftText); + joinNodeAsText->GetData(rightText); + } + else + { + keepNodeAsText->GetData(rightText); + joinNodeAsText->GetData(leftText); + } + leftText += rightText; + keepNodeAsText->SetData(leftText); + } + else + { // otherwise it's an interior node, so shuffle around the children + nsCOMPtr childNodes; + result = aNodeToJoin->GetChildNodes(getter_AddRefs(childNodes)); + if ((NS_SUCCEEDED(result)) && (childNodes)) + { + PRUint32 i; + PRUint32 childCount=0; + childNodes->GetLength(&childCount); + nsCOMPtr firstNode; //only used if aNodeToKeepIsFirst is false + if (PR_FALSE==aNodeToKeepIsFirst) + { // remember the first child in aNodeToKeep, we'll insert all the children of aNodeToJoin in front of it + result = aNodeToKeep->GetFirstChild(getter_AddRefs(firstNode)); + // GetFirstChild returns nsnull firstNode if aNodeToKeep has no children, that's ok. + } + nsCOMPtr resultNode; + for (i=0; ((NS_SUCCEEDED(result)) && (iAppendChild(childNode, getter_AddRefs(resultNode)); - } - else - { // prepend children of aNodeToJoin - result = aNodeToKeep->InsertBefore(childNode, firstNode, getter_AddRefs(resultNode)); + nsCOMPtr childNode; + result = childNodes->Item(i, getter_AddRefs(childNode)); + if ((NS_SUCCEEDED(result)) && (childNode)) + { + if (PR_TRUE==aNodeToKeepIsFirst) + { // append children of aNodeToJoin + result = aNodeToKeep->AppendChild(childNode, getter_AddRefs(resultNode)); + } + else + { // prepend children of aNodeToJoin + result = aNodeToKeep->InsertBefore(childNode, firstNode, getter_AddRefs(resultNode)); + } } } } - if (NS_SUCCEEDED(result)) - { // delete the extra node - result = aParent->RemoveChild(aNodeToJoin, getter_AddRefs(resultNode)); + else if (!childNodes) { + result = NS_ERROR_NULL_POINTER; } } + if (NS_SUCCEEDED(result)) + { // delete the extra node + nsCOMPtr resultNode; + result = aParent->RemoveChild(aNodeToJoin, getter_AddRefs(resultNode)); + } } else result = NS_ERROR_INVALID_ARG; diff --git a/editor/libeditor/base/nsEditor.h b/editor/libeditor/base/nsEditor.h index a640705777d..045c7ab1c60 100644 --- a/editor/libeditor/base/nsEditor.h +++ b/editor/libeditor/base/nsEditor.h @@ -21,6 +21,7 @@ #include "prmon.h" #include "nsIEditor.h" +#include "nsIEditorSupport.h" #include "nsIContextLoader.h" #include "nsIDOMDocument.h" #include "nsIDOMEventListener.h" @@ -28,7 +29,6 @@ #include "nsITransactionManager.h" #include "TransactionFactory.h" #include "nsRepository.h" -//#include "nsISelection.h" class nsIDOMCharacterData; class nsIDOMRange; @@ -72,7 +72,7 @@ inline Property::Property(nsIAtom *aPropName, nsIAtom *aValue, PRBool aAppliesTo * 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. */ -class nsEditor : public nsIEditor +class nsEditor : public nsIEditor, public nsIEditorSupport { private: nsIPresShell *mPresShell; @@ -104,6 +104,8 @@ public: virtual nsresult GetDocument(nsIDOMDocument **aDoc); + virtual nsresult GetSelection(nsIDOMSelection **aSelection); + virtual nsresult SetProperties(nsVoidArray *aPropList); virtual nsresult GetProperties(nsVoidArray *aPropList); @@ -133,9 +135,7 @@ public: virtual nsresult DeleteSelection(nsIEditor::Direction aDir); virtual nsresult SplitNode(nsIDOMNode * aExistingRightNode, - PRInt32 aOffset, - nsIDOMNode * aNewLeftNode, - nsIDOMNode * aParent); + PRInt32 aOffset); virtual nsresult JoinNodes(nsIDOMNode * aNodeToKeep, nsIDOMNode * aNodeToJoin, @@ -232,10 +232,20 @@ protected: PRUint32 aOffset, SplitElementTxn **aTxn); + virtual nsresult SplitNodeImpl(nsIDOMNode * aExistingRightNode, + PRInt32 aOffset, + nsIDOMNode * aNewLeftNode, + nsIDOMNode * aParent); + virtual nsresult CreateTxnForJoinNode(nsIDOMNode *aLeftNode, nsIDOMNode *aRightNode, JoinElementTxn **aTxn); + virtual nsresult JoinNodesImpl(nsIDOMNode * aNodeToKeep, + nsIDOMNode * aNodeToJoin, + nsIDOMNode * aParent, + PRBool aNodeToKeepIsFirst); + #if 0 nsresult CreateTxnToHandleEnterKey(EditAggregateTxn **aTxn); #endif diff --git a/editor/public/nsIEditor.h b/editor/public/nsIEditor.h index 3d1777b70dc..cc8de89e4c3 100644 --- a/editor/public/nsIEditor.h +++ b/editor/public/nsIEditor.h @@ -44,6 +44,7 @@ Editor interface to outside world { 0x8f, 0x4c, 0x0, 0x60, 0x8, 0x15, 0x9b, 0xc } } class nsIDOMDocument; +class nsIDOMSelection; class nsIPresShell; class nsString; @@ -79,6 +80,13 @@ public: */ virtual nsresult GetDocument(nsIDOMDocument **aDoc)=0; + /** + * return the DOM Selection for the presentation shell that has focus + * (or most recently had focus.) + * @param aSelection [OUT] the dom interface for the selection + */ + virtual nsresult GetSelection(nsIDOMSelection **aSelection)=0; + /** * SetAttribute() sets the attribute of aElement. * No checking is done to see if aAttribute is a legal attribute of the node, @@ -168,12 +176,9 @@ public: * @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 */ virtual nsresult SplitNode(nsIDOMNode * aExistingRightNode, - PRInt32 aOffset, - nsIDOMNode * aNewLeftNode, - nsIDOMNode * aParent)=0; + PRInt32 aOffset)=0; /** * JoinNodes() takes 2 nodes and merge their content|children.