From 9a004fa0f075df549accf4ffcdccbc002d69782e Mon Sep 17 00:00:00 2001 From: "buster%netscape.com" Date: Wed, 5 May 1999 04:05:19 +0000 Subject: [PATCH] 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. git-svn-id: svn://10.0.0.236/trunk@30367 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/editor/base/CreateElementTxn.cpp | 8 +- mozilla/editor/base/JoinElementTxn.cpp | 25 +- mozilla/editor/base/SplitElementTxn.cpp | 49 +- mozilla/editor/base/nsEditProperty.cpp | 41 +- mozilla/editor/base/nsEditor.cpp | 830 ++++++++++++------ mozilla/editor/base/nsEditor.h | 195 +++- .../editor/base/nsEditorEventListeners.cpp | 35 +- mozilla/editor/base/nsHTMLEditor.cpp | 580 ++++++++---- mozilla/editor/base/nsHTMLEditor.h | 16 +- mozilla/editor/base/nsIEditProperty.h | 1 + mozilla/editor/base/nsTextEditRules.cpp | 78 +- mozilla/editor/base/nsTextEditRules.h | 2 - mozilla/editor/base/nsTextEditor.cpp | 317 +------ mozilla/editor/base/nsTextEditor.h | 33 - .../libeditor/base/CreateElementTxn.cpp | 8 +- .../editor/libeditor/base/JoinElementTxn.cpp | 25 +- .../editor/libeditor/base/SplitElementTxn.cpp | 49 +- mozilla/editor/libeditor/base/nsEditor.cpp | 830 ++++++++++++------ mozilla/editor/libeditor/base/nsEditor.h | 195 +++- .../editor/libeditor/base/nsIEditProperty.h | 1 + .../editor/libeditor/html/nsEditProperty.cpp | 41 +- .../editor/libeditor/html/nsHTMLEditor.cpp | 580 ++++++++---- mozilla/editor/libeditor/html/nsHTMLEditor.h | 16 +- .../libeditor/text/nsEditorEventListeners.cpp | 35 +- .../editor/libeditor/text/nsTextEditRules.cpp | 78 +- .../editor/libeditor/text/nsTextEditRules.h | 2 - mozilla/editor/public/nsIEditor.h | 17 +- mozilla/editor/public/nsIHTMLEditor.h | 6 +- mozilla/editor/public/nsITextEditor.h | 1 - 29 files changed, 2484 insertions(+), 1610 deletions(-) diff --git a/mozilla/editor/base/CreateElementTxn.cpp b/mozilla/editor/base/CreateElementTxn.cpp index 5bdd71f2797..25cd713c707 100644 --- a/mozilla/editor/base/CreateElementTxn.cpp +++ b/mozilla/editor/base/CreateElementTxn.cpp @@ -17,12 +17,12 @@ */ #include "CreateElementTxn.h" +#include "nsEditor.h" #include "nsIDOMDocument.h" #include "nsIDOMNodeList.h" #include "nsIDOMSelection.h" #include "nsIDOMText.h" #include "nsIDOMElement.h" -#include "nsIEditorSupport.h" #ifdef NS_DEBUG static PRBool gNoisy = PR_FALSE; @@ -125,7 +125,7 @@ NS_IMETHODIMP CreateElementTxn::Do(void) nsresult selectionResult = mEditor->GetSelection(getter_AddRefs(selection)); if (NS_SUCCEEDED(selectionResult) && selection) { PRInt32 offset=0; - nsIEditorSupport::GetChildOffset(mNewNode, mParent, offset); + nsEditor::GetChildOffset(mNewNode, mParent, offset); selectionResult = selection->Collapse(mParent, offset); 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) { PRInt32 offset=0; if (mRefNode) { - nsIEditorSupport::GetChildOffset(mRefNode, mParent, offset); + nsEditor::GetChildOffset(mRefNode, mParent, offset); } selectionResult = selection->Collapse(mParent, offset); 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)); if (NS_SUCCEEDED(result) && selection) { PRInt32 offset=0; - nsIEditorSupport::GetChildOffset(mNewNode, mParent, offset); + nsEditor::GetChildOffset(mNewNode, mParent, offset); nsresult selectionResult = selection->Collapse(mParent, offset); NS_ASSERTION((NS_SUCCEEDED(selectionResult)), "selection could not be collapsed after undo of insert."); } diff --git a/mozilla/editor/base/JoinElementTxn.cpp b/mozilla/editor/base/JoinElementTxn.cpp index cee9303ebad..ef9e17cb7a6 100644 --- a/mozilla/editor/base/JoinElementTxn.cpp +++ b/mozilla/editor/base/JoinElementTxn.cpp @@ -17,10 +17,10 @@ */ #include "JoinElementTxn.h" +#include "nsEditor.h" #include "nsIDOMNodeList.h" #include "nsIDOMCharacterData.h" #include "nsIDOMSelection.h" -#include "nsIEditorSupport.h" #ifdef NS_DEBUG static PRBool gNoisy = PR_FALSE; @@ -28,9 +28,6 @@ static PRBool gNoisy = PR_FALSE; static const PRBool gNoisy = PR_FALSE; #endif -static NS_DEFINE_IID(kIEditorSupportIID, NS_IEDITORSUPPORT_IID); - - JoinElementTxn::JoinElementTxn() : EditTxn() { @@ -84,19 +81,15 @@ NS_IMETHODIMP JoinElementTxn::Do(void) leftNodeAsText->GetLength(&mOffset); } } - nsCOMPtr editor; - result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); - if (NS_SUCCEEDED(result) && editor) { - result = editor->JoinNodesImpl(mRightNode, mLeftNode, mParent, PR_FALSE); - if (NS_SUCCEEDED(result)) + result = nsEditor::JoinNodesImpl(mRightNode, mLeftNode, mParent, PR_FALSE); + if (NS_SUCCEEDED(result)) + { + if (gNoisy) { printf(" left node = %p removed\n", mLeftNode.get()); } + nsCOMPtrselection; + mEditor->GetSelection(getter_AddRefs(selection)); + if (selection) { - if (gNoisy) { printf(" left node = %p removed\n", mLeftNode.get()); } - nsCOMPtrselection; - mEditor->GetSelection(getter_AddRefs(selection)); - if (selection) - { - selection->Collapse(mRightNode, mOffset); - } + selection->Collapse(mRightNode, mOffset); } } } diff --git a/mozilla/editor/base/SplitElementTxn.cpp b/mozilla/editor/base/SplitElementTxn.cpp index b776a8f0630..bbc81ece56d 100644 --- a/mozilla/editor/base/SplitElementTxn.cpp +++ b/mozilla/editor/base/SplitElementTxn.cpp @@ -17,10 +17,10 @@ */ #include "SplitElementTxn.h" +#include "nsEditor.h" #include "nsIDOMNode.h" #include "nsIDOMSelection.h" #include "nsIDOMCharacterData.h" -#include "nsIEditorSupport.h" #ifdef NS_DEBUG static PRBool gNoisy = PR_FALSE; @@ -28,7 +28,6 @@ static PRBool gNoisy = PR_FALSE; static const PRBool gNoisy = PR_FALSE; #endif -static NS_DEFINE_IID(kIEditorSupportIID, NS_IEDITORSUPPORT_IID); // note that aEditor is not refcounted SplitElementTxn::SplitElementTxn() @@ -69,19 +68,14 @@ NS_IMETHODIMP SplitElementTxn::Do(void) // insert the new node if ((NS_SUCCEEDED(result)) && (mParent)) { - nsCOMPtr editor; - result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); - if (NS_SUCCEEDED(result) && editor) + result = nsEditor::SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent); + if (NS_SUCCEEDED(result) && mNewLeftNode) { - result = editor->SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent); - if (NS_SUCCEEDED(result) && mNewLeftNode) + nsCOMPtrselection; + mEditor->GetSelection(getter_AddRefs(selection)); + if (selection) { - nsCOMPtrselection; - mEditor->GetSelection(getter_AddRefs(selection)); - if (selection) - { - selection->Collapse(mNewLeftNode, mOffset); - } + selection->Collapse(mNewLeftNode, mOffset); } } else { @@ -105,25 +99,20 @@ NS_IMETHODIMP SplitElementTxn::Undo(void) // this assumes Do inserted the new node in front of the prior existing node nsresult result; - nsCOMPtr editor; - result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); - if (NS_SUCCEEDED(result) && editor) + result = nsEditor::JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent, PR_FALSE); + if (gNoisy) + { + 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("** after join left child node %p into right node %p\n", mNewLeftNode.get(), mExistingRightNode.get()); - if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG - } - if (NS_SUCCEEDED(result)) + if (gNoisy) { printf(" left node = %p removed\n", mNewLeftNode.get()); } + nsCOMPtrselection; + mEditor->GetSelection(getter_AddRefs(selection)); + if (selection) { - if (gNoisy) { printf(" left node = %p removed\n", mNewLeftNode.get()); } - nsCOMPtrselection; - mEditor->GetSelection(getter_AddRefs(selection)); - if (selection) - { - selection->Collapse(mExistingRightNode, mOffset); - } + selection->Collapse(mExistingRightNode, mOffset); } } else { diff --git a/mozilla/editor/base/nsEditProperty.cpp b/mozilla/editor/base/nsEditProperty.cpp index 13068ce4335..f19e50f4902 100644 --- a/mozilla/editor/base/nsEditProperty.cpp +++ b/mozilla/editor/base/nsEditProperty.cpp @@ -43,6 +43,7 @@ nsIAtom * nsIEditProperty::tt; nsIAtom * nsIEditProperty::u; // block tags nsIAtom * nsIEditProperty::blockquote; +nsIAtom * nsIEditProperty::br; nsIAtom * nsIEditProperty::h1; nsIAtom * nsIEditProperty::h2; // properties @@ -56,28 +57,29 @@ void nsEditProperty::InstanceInit() { // tags - nsIEditProperty::a = NS_NewAtom("A"); - nsIEditProperty::b = NS_NewAtom("B"); - nsIEditProperty::big = NS_NewAtom("BIG"); - nsIEditProperty::font = NS_NewAtom("FONT"); - nsIEditProperty::i = NS_NewAtom("I"); - nsIEditProperty::span = NS_NewAtom("SPAN"); - nsIEditProperty::small =NS_NewAtom("SMALL"); - nsIEditProperty::strike=NS_NewAtom("STRIKE"); - nsIEditProperty::sub = NS_NewAtom("SUB"); - nsIEditProperty::sup = NS_NewAtom("SUP"); - nsIEditProperty::tt = NS_NewAtom("TT"); - nsIEditProperty::u = NS_NewAtom("U"); + nsIEditProperty::a = NS_NewAtom("a"); + nsIEditProperty::b = NS_NewAtom("b"); + nsIEditProperty::big = NS_NewAtom("big"); + nsIEditProperty::font = NS_NewAtom("font"); + nsIEditProperty::i = NS_NewAtom("i"); + nsIEditProperty::span = NS_NewAtom("span"); + nsIEditProperty::small =NS_NewAtom("small"); + nsIEditProperty::strike=NS_NewAtom("strike"); + nsIEditProperty::sub = NS_NewAtom("sub"); + nsIEditProperty::sup = NS_NewAtom("sup"); + nsIEditProperty::tt = NS_NewAtom("tt"); + nsIEditProperty::u = NS_NewAtom("u"); // tags - nsIEditProperty::blockquote = NS_NewAtom("BLOCKQUOTE"); - nsIEditProperty::h1 = NS_NewAtom("H1"); - nsIEditProperty::h2 = NS_NewAtom("H2"); + nsIEditProperty::blockquote = NS_NewAtom("blockquote"); + nsIEditProperty::br = NS_NewAtom("br"); + nsIEditProperty::h1 = NS_NewAtom("h1"); + nsIEditProperty::h2 = NS_NewAtom("h2"); // properties - nsIEditProperty::color= NS_NewAtom("COLOR"); - nsIEditProperty::face = NS_NewAtom("FACE"); - nsIEditProperty::size = NS_NewAtom("SIZE"); + nsIEditProperty::color= NS_NewAtom("color"); + nsIEditProperty::face = NS_NewAtom("face"); + nsIEditProperty::size = NS_NewAtom("size"); // special - nsIEditProperty::allProperties = new nsString("moz_AllProperties"); + nsIEditProperty::allProperties = new nsString("moz_allproperties"); } void @@ -98,6 +100,7 @@ nsEditProperty::InstanceShutdown() NS_IF_RELEASE(nsIEditProperty::u); // tags NS_IF_RELEASE(nsIEditProperty::blockquote); + NS_IF_RELEASE(nsIEditProperty::br); NS_IF_RELEASE(nsIEditProperty::h1); NS_IF_RELEASE(nsIEditProperty::h2); // properties diff --git a/mozilla/editor/base/nsEditor.cpp b/mozilla/editor/base/nsEditor.cpp index 77879a104a8..70baa157ba1 100644 --- a/mozilla/editor/base/nsEditor.cpp +++ b/mozilla/editor/base/nsEditor.cpp @@ -19,6 +19,7 @@ #include "nsIDOMDocument.h" #include "nsEditor.h" +#include "nsIEditProperty.h" // to be removed XXX #include "nsIDOMText.h" #include "nsIDOMElement.h" #include "nsIDOMAttr.h" @@ -41,6 +42,7 @@ #include "nsIEnumerator.h" #include "nsIAtom.h" #include "nsVoidArray.h" +#include "nsISupportsArray.h" #include "nsICaret.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(kIDOMSelectionIID, NS_IDOMSELECTION_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(kIDocumentIID, NS_IDOCUMENT_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(kIHTMLEditFactoryIID, NS_IHTMLEDITORFACTORY_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); @@ -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_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 -static PRBool gNoisy = PR_FALSE; +static PRBool gNoisy = PR_TRUE; #else static const PRBool gNoisy = PR_FALSE; #endif @@ -324,7 +329,7 @@ nsEditor::~nsEditor() -//BEGIN nsIEditor interface implementations +// BEGIN nsEditor core implementation NS_IMPL_ADDREF(nsEditor) @@ -351,11 +356,6 @@ 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; } @@ -665,109 +665,6 @@ nsEditor::InsertBreak() //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 node; - nsCOMPtr 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 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 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 answer; - - aNode->GetNodeType(&mType); - - if (nsIDOMNode::ELEMENT_NODE == mType) { - if (NS_SUCCEEDED(aNode->HasChildNodes(&mCNodes)) && PR_TRUE == mCNodes) - { - nsCOMPtr node1; - nsCOMPtr 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 nsEditor::Do(nsITransaction *aTxn) @@ -1510,7 +1407,7 @@ NS_IMETHODIMP nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtrGetParentNode(getter_AddRefs(parentSelectedNode)); selectedParentNodeAsText->GetLength(&selectedNodeContentCount); - nsIEditorSupport::GetChildOffset(selectedNode, parentSelectedNode, indexOfTextNodeInParent); + GetChildOffset(selectedNode, parentSelectedNode, indexOfTextNodeInParent); if ((offsetOfSelectedNode!=0) && (((PRUint32)offsetOfSelectedNode)!=selectedNodeContentCount)) { @@ -1518,7 +1415,7 @@ NS_IMETHODIMP nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtrGetPreviousSibling(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 parent(do_QueryInterface(aCurrentNode)); - do { - nsCOMPtr 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 parent(do_QueryInterface(aCurrentNode)); - do { - nsCOMPtr 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 resultNode(do_QueryInterface(aCurrentNode)); - PRBool hasChildren; - resultNode->HasChildNodes(&hasChildren); - while ((NS_SUCCEEDED(result)) && (PR_TRUE==hasChildren)) - { - nsCOMPtr 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 resultNode(do_QueryInterface(aCurrentNode)); - PRBool hasChildren; - resultNode->HasChildNodes(&hasChildren); - while ((NS_SUCCEEDED(result)) && (PR_TRUE==hasChildren)) - { - nsCOMPtr temp(resultNode); - temp->GetFirstChild(getter_AddRefs(resultNode)); - resultNode->HasChildNodes(&hasChildren); - } - - if (NS_SUCCEEDED(result)) { - *aResultNode = resultNode; - NS_ADDREF(*aResultNode); - } - return result; -} NS_IMETHODIMP nsEditor::SplitNode(nsIDOMNode * aNode, @@ -2037,7 +1832,12 @@ NS_IMETHODIMP nsEditor::CreateTxnForJoinNode(nsIDOMNode *aLeftNode, return result; } -NS_IMETHODIMP + +// END nsEditor core implementation + +// BEGIN nsEditor public static helper methods + +nsresult nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode, PRInt32 aOffset, nsIDOMNode* aNewLeftNode, @@ -2113,7 +1913,7 @@ nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode, return result; } -NS_IMETHODIMP +nsresult nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep, nsIDOMNode * aNodeToJoin, nsIDOMNode * aParent, @@ -2203,7 +2003,8 @@ nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep, 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"); nsresult result = NS_ERROR_NULL_POINTER; @@ -2236,8 +2037,478 @@ nsresult nsIEditorSupport::GetChildOffset(nsIDOMNode *aChild, nsIDOMNode *aParen 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; + nsCOMPtrnodeAsChar; + nodeAsChar = do_QueryInterface(aNode); + if (nodeAsChar) { + nodeAsChar->GetLength(&aCount); + } + else + { + PRBool hasChildNodes; + aNode->HasChildNodes(&hasChildNodes); + if (PR_TRUE==hasChildNodes) + { + nsCOMPtrnodeList; + 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; + nsCOMPtrelement; + 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; + nsCOMPtrparent; + nsCOMPtrtemp; + 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; + + nsCOMPtrsibling; + result = aChild->GetPreviousSibling(getter_AddRefs(sibling)); + while ((NS_SUCCEEDED(result)) && sibling) + { + PRBool isInline; + IsNodeInline(sibling, isInline); + if (PR_FALSE==isInline) + { + nsCOMPtrnodeAsText = 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) + { + nsCOMPtrnodeAsText = 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; + nsCOMPtriter; + result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull, + kIContentIteratorIID, getter_AddRefs(iter)); + if ((NS_SUCCEEDED(result)) && iter) + { + nsCOMPtr lastRange; + iter->Init(aRange); + nsCOMPtr currentContent; + iter->CurrentNode(getter_AddRefs(currentContent)); + while (NS_COMFALSE == iter->IsDone()) + { + nsCOMPtrcurrentNode = do_QueryInterface(currentContent); + if (currentNode) + { + nsCOMPtr currentContentTag; + currentContent->GetTag(*getter_AddRefs(currentContentTag)); + //
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) + { + nsCOMPtrleftNode; + nsCOMPtrrightNode; + 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 lastStartNode; + nsCOMPtr 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 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 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; } + + nsCOMPtriter; + 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) + { + nsCOMPtrstartContent; + startContent = do_QueryInterface(aStartNode); + nsCOMPtrendContent; + endContent = do_QueryInterface(aEndNode); + if (startContent && endContent) + { + iter->Init(aRange); + nsCOMPtr content; + iter->CurrentNode(getter_AddRefs(content)); + while (NS_COMFALSE == iter->IsDone()) + { + if ((content.get() != startContent.get()) && + (content.get() != endContent.get())) + { + nsCOMPtrcurrentNode; + currentNode = do_QueryInterface(content); + PRBool isInline=PR_FALSE; + IsNodeInline(currentNode, isInline); + if (PR_FALSE==isInline) + { + nsCOMPtrnodeAsText; + 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 parent(do_QueryInterface(aCurrentNode)); + do { + nsCOMPtr 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 parent(do_QueryInterface(aCurrentNode)); + do { + nsCOMPtr 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 resultNode(do_QueryInterface(aCurrentNode)); + PRBool hasChildren; + resultNode->HasChildNodes(&hasChildren); + while ((NS_SUCCEEDED(result)) && (PR_TRUE==hasChildren)) + { + nsCOMPtr 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 resultNode(do_QueryInterface(aCurrentNode)); + PRBool hasChildren; + resultNode->HasChildNodes(&hasChildren); + while ((NS_SUCCEEDED(result)) && (PR_TRUE==hasChildren)) + { + nsCOMPtr 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) +{ + nsCOMPtrelement; + 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; + nsCOMPtrelement; + 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 + { + nsCOMPtrtext; + 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 nodeAsContent(aCellNode); - if (nodeAsContent) - { // get the frame from the content interface - nsISupports *layoutObject=nsnull; // frames are not ref counted, so don't use an nsCOMPtr - result = aPresShell->GetLayoutObjectFor(nodeAsContent, &layoutObject); - if ((NS_SUCCEEDED(result)) && (nsnull!=layoutObject)) - { // get the table cell interface from the frame - nsITableCellLayout *cellLayoutObject=nsnull; // again, frames are not ref-counted - result = layoutObject->QueryInterface(nsITableCellLayout::GetIID(), (void**)(&cellLayoutObject)); - if ((NS_SUCCEEDED(result)) && (nsnull!=cellLayoutObject)) - { // get the index - result = cellLayoutObject->GetColIndex(aCellIndex); - } + nsresult result=NS_OK; + + if (!aStartNode) + return NS_ERROR_NULL_POINTER; + if (!aResult) + return NS_ERROR_NULL_POINTER; + + nsCOMPtr element; + *aResult = nsnull; + nsCOMPtr childNode; + result = aStartNode->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 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 answer; + + aNode->GetNodeType(&mType); + + if (nsIDOMNode::ELEMENT_NODE == mType) { + if (NS_SUCCEEDED(aNode->HasChildNodes(&mCNodes)) && PR_TRUE == mCNodes) + { + nsCOMPtr node1; + nsCOMPtr 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 { - result = NS_ERROR_NULL_POINTER; + else if (nsIDOMNode::TEXT_NODE == mType) { + 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) { @@ -2601,3 +2926,4 @@ nsEditor::SetPreeditText(const nsString& aStringToInsert) EndTransaction(); return result; } + diff --git a/mozilla/editor/base/nsEditor.h b/mozilla/editor/base/nsEditor.h index acd0fdae1bf..86d42bbfb37 100644 --- a/mozilla/editor/base/nsEditor.h +++ b/mozilla/editor/base/nsEditor.h @@ -21,7 +21,6 @@ #include "prmon.h" #include "nsIEditor.h" -#include "nsIEditorSupport.h" #include "nsIContextLoader.h" #include "nsIDOMDocument.h" #include "nsIDOMEventListener.h" @@ -46,6 +45,7 @@ class SplitElementTxn; class JoinElementTxn; class EditAggregateTxn; class nsVoidArray; +class nsISupportsArray; //This is the monitor for the editor. PRMonitor *getEditorMonitor(); @@ -56,7 +56,7 @@ PRMonitor *getEditorMonitor(); * 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, public nsIEditorSupport +class nsEditor : public nsIEditor { private: nsIPresShell *mPresShell; @@ -75,6 +75,10 @@ protected: nsIDOMDocument * mDoc; public: + + const static char* nsEditor::kMOZEditorBogusNodeAttr; + const static char* nsEditor::kMOZEditorBogusNodeValue; + /** The default constructor. This should suffice. the setting of the interfaces is done * after the construction of the editor class. */ @@ -186,32 +190,6 @@ public: /*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*/ protected: /** create a transaction for setting aAttribute to aValue on aElement @@ -278,28 +256,10 @@ protected: PRUint32 aOffset, SplitElementTxn **aTxn); - NS_IMETHOD SplitNodeImpl(nsIDOMNode * aExistingRightNode, - PRInt32 aOffset, - nsIDOMNode * aNewLeftNode, - nsIDOMNode * aParent); - NS_IMETHOD CreateTxnForJoinNode(nsIDOMNode *aLeftNode, nsIDOMNode *aRightNode, 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 * Used by all methods that need to delete current selection, * then insert something new to replace it @@ -321,11 +281,152 @@ protected: // of an error in Gecko which is not rendering the // document after a change via the DOM - gpk 2/13/99 void HACKForceRedraw(void); + PRBool mIMEFirstTransaction; - NS_IMETHOD DeleteSelectionAndPrepareToCreateNode(nsCOMPtr &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. + *
tags separate block content sections. So the HTML markup: + *
+    *      

text1
text2text3

+ *
+ * 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); + }; diff --git a/mozilla/editor/base/nsEditorEventListeners.cpp b/mozilla/editor/base/nsEditorEventListeners.cpp index 09c6ec09673..d2f59355f9b 100644 --- a/mozilla/editor/base/nsEditorEventListeners.cpp +++ b/mozilla/editor/base/nsEditorEventListeners.cpp @@ -25,6 +25,7 @@ #include "nsIDOMCharacterData.h" #include "nsIEditProperty.h" #include "nsISupportsArray.h" +#include "nsVoidArray.h" #include "nsString.h" #include "nsIStringStream.h" @@ -599,7 +600,39 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr nsCOMPtrhtmlEditor; htmlEditor = do_QueryInterface(mEditor); 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) + { + nsCOMPtrhtmlEditor; + 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; iToNewCString(); + printf("%s ", tagCString); + delete [] tagCString; + } + printf("\n"); + } } } } diff --git a/mozilla/editor/base/nsHTMLEditor.cpp b/mozilla/editor/base/nsHTMLEditor.cpp index 20249dd4c6a..22ce3578337 100644 --- a/mozilla/editor/base/nsHTMLEditor.cpp +++ b/mozilla/editor/base/nsHTMLEditor.cpp @@ -40,7 +40,6 @@ #include "nsIComponentManager.h" #include "nsIServiceManager.h" -#include "nsITableCellLayout.h" //For GetColIndexForCell 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); #ifdef NS_DEBUG -static PRBool gNoisy = PR_FALSE; +static PRBool gNoisy = PR_TRUE; #else static const PRBool gNoisy = PR_FALSE; #endif @@ -205,7 +204,7 @@ NS_IMETHODIMP nsHTMLEditor::InsertBreak() if (-1==offsetInParent) { nextNode->GetParentNode(getter_AddRefs(parent)); - result = nsIEditorSupport::GetChildOffset(nextNode, parent, offsetInParent); + result = GetChildOffset(nextNode, parent, offsetInParent); if (NS_SUCCEEDED(result)) { 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)) { nsCOMPtr 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 - nsISupportsArray *subRanges; - result = NS_NewISupportsArray(&subRanges); - if ((NS_SUCCEEDED(result)) && subRanges) + nsISupportsArray *blockSections; + result = NS_NewISupportsArray(&blockSections); + if ((NS_SUCCEEDED(result)) && blockSections) { - result = GetBlockRanges(range, subRanges); + result = GetBlockSectionsForRange(range, blockSections); if (NS_SUCCEEDED(result)) { nsIDOMRange *subRange; - subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); + subRange = (nsIDOMRange *)(blockSections->ElementAt(0)); while (subRange && (NS_SUCCEEDED(result))) { nsCOMPtrstartParent; @@ -418,17 +417,19 @@ nsHTMLEditor::GetParagraphStyle(nsStringArray *aTagList) { nsAutoString 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); } } } NS_RELEASE(subRange); - subRanges->RemoveElementAt(0); - subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); + blockSections->RemoveElementAt(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)) { nsCOMPtr 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 result = ReParentContentOfRange(range, aParentTag, eInsertParent); } @@ -510,47 +511,30 @@ nsHTMLEditor::ReplaceBlockParent(nsString& aParentTag) if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) { nsCOMPtr 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 result = ReParentContentOfRange(range, aParentTag, eReplaceParent); } } 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 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 nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode, nsString &aParentTag, BlockTransformationType aTransformation) { 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 nsCOMPtrblockParentElement; nsCOMPtrnodeToReParent; // 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 // XXX: how to you know it's an insertion point??? PRInt32 offsetInParent=0; - result = nsIEditorSupport::GetChildOffset(nodeToReParent, blockParentNode, offsetInParent); + result = GetChildOffset(nodeToReParent, blockParentNode, offsetInParent); NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset"); // otherwise, just create the block parent at the selection result = nsTextEditor::CreateNode(aParentTag, blockParentNode, offsetInParent, @@ -654,10 +638,14 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, nsString &aParentTag, nsIDOMNode *aBlockParentNode, nsString &aBlockParentTag, - BlockTransformationType aTranformation, + BlockTransformationType aTransformation, nsIDOMNode **aNewParentNode) { if (!aNode || !aBlockParentNode || !aNewParentNode) { return NS_ERROR_NULL_POINTER; } + nsCOMPtr blockParentNode = do_QueryInterface(aBlockParentNode); + PRBool removeBlockParent = PR_FALSE; + PRBool removeBreakBefore = PR_FALSE; + PRBool removeBreakAfter = PR_FALSE; nsCOMPtrancestor; nsresult result = aNode->GetParentNode(getter_AddRefs(ancestor)); nsCOMPtrpreviousAncestor = do_QueryInterface(aNode); @@ -675,46 +663,87 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, } // now, previousAncestor is the node we are operating on nsCOMPtrleftNode, rightNode; - result = GetBlockDelimitedContent(previousAncestor, - getter_AddRefs(leftNode), - getter_AddRefs(rightNode)); + result = GetBlockSection(previousAncestor, + getter_AddRefs(leftNode), + getter_AddRefs(rightNode)); if ((NS_SUCCEEDED(result)) && leftNode && rightNode) { - PRInt32 offsetInParent=0; - if (eInsertParent==aTranformation) + // determine some state for managing
s around the new block + 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 + nsCOMPtrblockParentElement = 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"); - result = nsTextEditor::CreateNode(aParentTag, aBlockParentNode, offsetInParent, aNewParentNode); - if (gNoisy) { printf("created a node in aBlockParentNode at offset %d\n", offsetInParent); } + result = nsTextEditor::CreateNode(aParentTag, blockParentNode, offsetInParent, aNewParentNode); + if (gNoisy) { printf("created a node in blockParentNode at offset %d\n", offsetInParent); } } else { nsCOMPtr grandParent; - result = aBlockParentNode->GetParentNode(getter_AddRefs(grandParent)); + result = blockParentNode->GetParentNode(getter_AddRefs(grandParent)); if ((NS_SUCCEEDED(result)) && grandParent) { nsCOMPtrfirstChildNode, lastChildNode; - aBlockParentNode->GetFirstChild(getter_AddRefs(firstChildNode)); - aBlockParentNode->GetLastChild(getter_AddRefs(lastChildNode)); + blockParentNode->GetFirstChild(getter_AddRefs(firstChildNode)); + blockParentNode->GetLastChild(getter_AddRefs(lastChildNode)); 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"); result = nsTextEditor::CreateNode(aParentTag, grandParent, offsetInParent, aNewParentNode); if (gNoisy) { printf("created a node in grandParent at offset %d\n", offsetInParent); } } else { - result = nsIEditorSupport::GetChildOffset(leftNode, aBlockParentNode, offsetInParent); + // We're in the case where the content of blockParentNode is separated by
's, + // creating multiple block content ranges. + // Split blockParentNode around the blockContent + if (gNoisy) { printf("splitting a node because of
s\n"); } + nsCOMPtr 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"); - result = nsTextEditor::CreateNode(aParentTag, aBlockParentNode, offsetInParent, aNewParentNode); - if (gNoisy) { printf("created a node in aBlockParentNode at offset %d\n", offsetInParent); } + result = nsTextEditor::CreateNode(aParentTag, blockParentNode, offsetInParent, aNewParentNode); + 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) - { // move all the children/contents of aBlockParentNode to aNewParentNode + { // move all the children/contents of blockParentNode to aNewParentNode nsCOMPtrchildNode = do_QueryInterface(rightNode); nsCOMPtrpreviousSiblingNode; while (NS_SUCCEEDED(result) && childNode) @@ -737,6 +766,73 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, childNode = do_QueryInterface(previousSiblingNode); } // end while loop } + // clean up the surrounding content to maintain vertical whitespace + if (NS_SUCCEEDED(result)) + { + // if the prior node is a
and we did something to change vertical whitespacing, delete the
+ nsCOMPtr brNode; + result = GetPriorNode(leftNode, getter_AddRefs(brNode)); + if (NS_SUCCEEDED(result) && brNode) + { + nsCOMPtr brContent = do_QueryInterface(brNode); + if (brContent) + { + nsCOMPtr brContentTag; + brContent->GetTag(*getter_AddRefs(brContentTag)); + if (nsIEditProperty::br==brContentTag) { + result = DeleteNode(brNode); + } + } + } + + // if the next node is a
and we did something to change vertical whitespacing, delete the
+ if (NS_SUCCEEDED(result)) + { + result = GetNextNode(rightNode, getter_AddRefs(brNode)); + if (NS_SUCCEEDED(result) && brNode) + { + nsCOMPtr brContent = do_QueryInterface(brNode); + if (brContent) + { + nsCOMPtr 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 childNodes; + result = blockParentNode->GetChildNodes(getter_AddRefs(childNodes)); + if ((NS_SUCCEEDED(result)) && (childNodes)) + { + nsCOMPtrgrandParent; + 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 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; } @@ -748,29 +844,30 @@ nsHTMLEditor::ReParentContentOfRange(nsIDOMRange *aRange, { if (!aRange) { return NS_ERROR_NULL_POINTER; } nsresult result; - nsISupportsArray *subRanges; - result = NS_NewISupportsArray(&subRanges); - if ((NS_SUCCEEDED(result)) && subRanges) + nsISupportsArray *blockSections; + result = NS_NewISupportsArray(&blockSections); + if ((NS_SUCCEEDED(result)) && blockSections) { - result = GetBlockRanges(aRange, subRanges); + result = GetBlockSectionsForRange(aRange, blockSections); if (NS_SUCCEEDED(result)) { nsIDOMRange *subRange; - subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); + subRange = (nsIDOMRange *)(blockSections->ElementAt(0)); while (subRange && (NS_SUCCEEDED(result))) { nsCOMPtrstartParent; result = subRange->GetStartParent(getter_AddRefs(startParent)); if (NS_SUCCEEDED(result) && startParent) { + if (gNoisy) { printf("ReParentContentOfRange calling ReParentContentOfNode\n"); } result = ReParentContentOfNode(startParent, aParentTag, aTranformation); } NS_RELEASE(subRange); - subRanges->RemoveElementAt(0); - subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); + blockSections->RemoveElementAt(0); + subRange = (nsIDOMRange *)(blockSections->ElementAt(0)); } } - NS_RELEASE(subRanges); + NS_RELEASE(blockSections); } return result; } @@ -793,10 +890,10 @@ nsHTMLEditor::CanContainBlock(nsString &aBlockChild, nsString &aBlockParent, PRB } NS_IMETHODIMP -nsHTMLEditor::RemoveBlockParent() +nsHTMLEditor::RemoveParagraphStyle() { if (gNoisy) { - printf("---------- nsHTMLEditor::RemoveBlockParent ----------\n"); + printf("---------- nsHTMLEditor::RemoveParagraphStyle ----------\n"); } nsresult result=NS_ERROR_NOT_INITIALIZED; @@ -815,65 +912,7 @@ nsHTMLEditor::RemoveBlockParent() if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) { nsCOMPtr range( do_QueryInterface(currentItem) ); - nsCOMPtrcommonParent; - result = range->GetCommonParent(getter_AddRefs(commonParent)); - if ((NS_SUCCEEDED(result)) && commonParent) - { - PRInt32 startOffset, endOffset; - range->GetStartOffset(&startOffset); - range->GetEndOffset(&endOffset); - nsCOMPtr startParent; nsCOMPtr 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 - nsCOMPtrblockParentElement; - 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 childNodes; - result = blockParentElement->GetChildNodes(getter_AddRefs(childNodes)); - if ((NS_SUCCEEDED(result)) && (childNodes)) - { - nsCOMPtrgrandParent; - 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 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)); - } - } - } + result = RemoveParagraphStyleFromRange(range); } } nsEditor::EndTransaction(); @@ -881,11 +920,93 @@ nsHTMLEditor::RemoveBlockParent() 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; + nsCOMPtrstartParent; + aRange->GetStartParent(getter_AddRefs(startParent)); + nsCOMPtrblockParentElement; + 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 childNodes; + result = blockParentElement->GetChildNodes(getter_AddRefs(childNodes)); + if ((NS_SUCCEEDED(result)) && (childNodes)) + { + nsCOMPtrgrandParent; + 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 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 nsHTMLEditor::RemoveParent(const nsString &aParentTag) { if (gNoisy) { - printf("---------- nsHTMLEditor::RemoveParent %s----------\n", aParentTag); + printf("---------- nsHTMLEditor::RemoveParagraphStyle ----------\n"); } nsresult result=NS_ERROR_NOT_INITIALIZED; @@ -904,68 +1025,7 @@ nsHTMLEditor::RemoveParent(const nsString &aParentTag) if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) { nsCOMPtr range( do_QueryInterface(currentItem) ); - nsCOMPtrcommonParent; - result = range->GetCommonParent(getter_AddRefs(commonParent)); - if ((NS_SUCCEEDED(result)) && commonParent) - { - PRInt32 startOffset, endOffset; - range->GetStartOffset(&startOffset); - range->GetEndOffset(&endOffset); - nsCOMPtr startParent; nsCOMPtr 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 - nsCOMPtrparentNode; - nsCOMPtrparentElement; - 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 childNodes; - result = parentElement->GetChildNodes(getter_AddRefs(childNodes)); - if ((NS_SUCCEEDED(result)) && (childNodes)) - { - nsCOMPtrgrandParent; - 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 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)); - } - } - } + result = RemoveParentFromRange(aParentTag, range); } } nsEditor::EndTransaction(); @@ -973,6 +1033,92 @@ nsHTMLEditor::RemoveParent(const nsString &aParentTag) 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; + nsCOMPtrstartParent; + result = aRange->GetStartParent(getter_AddRefs(startParent)); + if ((NS_SUCCEEDED(result)) && startParent) + { + nsCOMPtrparentNode; + nsCOMPtrparentElement; + 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 childNodes; + result = parentElement->GetChildNodes(getter_AddRefs(childNodes)); + if ((NS_SUCCEEDED(result)) && (childNodes)) + { + nsCOMPtrgrandParent; + 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 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 nsHTMLEditor::InsertLink(nsString& aURL) @@ -1331,6 +1477,62 @@ nsHTMLEditor::InsertElement(nsIDOMElement* aElement, PRBool aDeleteSelection, ns 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) { return nsTextEditor::BeginComposition(); @@ -1344,4 +1546,4 @@ NS_IMETHODIMP nsHTMLEditor::EndComposition(void) NS_IMETHODIMP nsHTMLEditor::SetCompositionString(const nsString& aCompositionString) { return nsTextEditor::SetCompositionString(aCompositionString); -} \ No newline at end of file +} diff --git a/mozilla/editor/base/nsHTMLEditor.h b/mozilla/editor/base/nsHTMLEditor.h index ffe65fb6402..1ad352f8868 100644 --- a/mozilla/editor/base/nsHTMLEditor.h +++ b/mozilla/editor/base/nsHTMLEditor.h @@ -107,7 +107,7 @@ public: NS_IMETHOD GetParagraphStyle(nsStringArray *aTagList); NS_IMETHOD AddBlockParent(nsString& aParentTag); NS_IMETHOD ReplaceBlockParent(nsString& aParentTag); - NS_IMETHOD RemoveBlockParent(); + NS_IMETHOD RemoveParagraphStyle(); NS_IMETHOD RemoveParent(const nsString &aParentTag); NS_IMETHOD InsertLink(nsString& aURL); @@ -163,8 +163,22 @@ protected: nsString &aParentTag, 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 IsRootTag(nsString &aTag, PRBool &aIsTag); + + NS_IMETHOD IsSubordinateBlock(nsString &aTag, PRBool &aIsTag); + + // EVENT LISTENERS AND COMMAND ROUTING NEEDS WORK // For now, the listners are tied to the nsTextEditor class // diff --git a/mozilla/editor/base/nsIEditProperty.h b/mozilla/editor/base/nsIEditProperty.h index b67f21575d1..e969c66a89d 100644 --- a/mozilla/editor/base/nsIEditProperty.h +++ b/mozilla/editor/base/nsIEditProperty.h @@ -73,6 +73,7 @@ SUP places text in superscript style // block tags static nsIAtom *blockquote; + static nsIAtom *br; static nsIAtom *h1; static nsIAtom *h2; diff --git a/mozilla/editor/base/nsTextEditRules.cpp b/mozilla/editor/base/nsTextEditRules.cpp index 603cf02bf70..8251aa3ea21 100644 --- a/mozilla/editor/base/nsTextEditRules.cpp +++ b/mozilla/editor/base/nsTextEditRules.cpp @@ -18,6 +18,7 @@ #include "nsTextEditRules.h" #include "nsTextEditor.h" +#include "nsEditor.h" #include "PlaceholderTxn.h" #include "InsertTextTxn.h" #include "nsCOMPtr.h" @@ -31,69 +32,8 @@ #include "nsIContent.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); -/******************************************************** - * Helper Functions - ********************************************************/ - -PRBool nsTextEditRules::NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag) -{ - nsCOMPtrelement; - 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; - nsCOMPtrelement; - 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 - { - nsCOMPtrtext; - 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, nsCOMPtrparent; aNode->GetParentNode(getter_AddRefs(parent)); PRInt32 offsetInParent; - nsIEditorSupport::GetChildOffset(aNode, parent, offsetInParent); + nsEditor::GetChildOffset(aNode, parent, offsetInParent); nsAutoString tag; aTag->ToString(tag); result = mEditor->CreateNode(tag, parent, offsetInParent, aNewNode); @@ -563,7 +503,7 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection, nsresult aResul result = bodyNode->GetFirstChild(getter_AddRefs(bodyChild)); while ((NS_SUCCEEDED(result)) && bodyChild) { - if (PR_TRUE==IsEditable(bodyChild)) + if (PR_TRUE==nsEditor::IsEditable(bodyChild)) { needsBogusContent = PR_FALSE; break; @@ -599,8 +539,8 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection, nsresult aResul newPElement = do_QueryInterface(mBogusNode); if (newPElement) { - nsAutoString att(kMOZEditorBogusNodeAttr); - nsAutoString val(kMOZEditorBogusNodeValue); + nsAutoString att(nsEditor::kMOZEditorBogusNodeAttr); + nsAutoString val(nsEditor::kMOZEditorBogusNodeValue); newPElement->SetAttribute(att, val); } } @@ -706,10 +646,10 @@ nsTextEditRules:: DidUndo(nsIDOMSelection *aSelection, nsresult aResult) element = do_QueryInterface(node); if (element) { - nsAutoString att(kMOZEditorBogusNodeAttr); + nsAutoString att(nsEditor::kMOZEditorBogusNodeAttr); nsAutoString val; (void)element->GetAttribute(att, val); - if (val.Equals(kMOZEditorBogusNodeValue)) { + if (val.Equals(nsEditor::kMOZEditorBogusNodeValue)) { mBogusNode = do_QueryInterface(element); } } @@ -752,10 +692,10 @@ nsTextEditRules::DidRedo(nsIDOMSelection *aSelection, nsresult aResult) element = do_QueryInterface(node); if (element) { - nsAutoString att(kMOZEditorBogusNodeAttr); + nsAutoString att(nsEditor::kMOZEditorBogusNodeAttr); nsAutoString val; (void)element->GetAttribute(att, val); - if (val.Equals(kMOZEditorBogusNodeValue)) { + if (val.Equals(nsEditor::kMOZEditorBogusNodeValue)) { mBogusNode = do_QueryInterface(element); } } diff --git a/mozilla/editor/base/nsTextEditRules.h b/mozilla/editor/base/nsTextEditRules.h index 08796b0dc86..459306a7e89 100644 --- a/mozilla/editor/base/nsTextEditRules.h +++ b/mozilla/editor/base/nsTextEditRules.h @@ -85,8 +85,6 @@ protected: nsresult DidRedo(nsIDOMSelection *aSelection, nsresult aResult); // helper functions - static PRBool NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag); - static PRBool IsEditable(nsIDOMNode *aNode); /** insert aNode into a new style node of type aTag. * aSelection is optional. If provided, aSelection is set to (aNode, 0) diff --git a/mozilla/editor/base/nsTextEditor.cpp b/mozilla/editor/base/nsTextEditor.cpp index f0962ab6bb5..e24119d2ef1 100644 --- a/mozilla/editor/base/nsTextEditor.cpp +++ b/mozilla/editor/base/nsTextEditor.cpp @@ -17,7 +17,6 @@ */ #include "nsTextEditor.h" -#include "nsIEditorSupport.h" #include "nsEditorEventListeners.h" #include "nsIEditProperty.h" #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); #ifdef NS_DEBUG -static PRBool gNoisy = PR_FALSE; +static PRBool gNoisy = PR_TRUE; #else static const PRBool gNoisy = PR_FALSE; #endif @@ -601,7 +600,7 @@ void nsTextEditor::IsTextPropertySetByContent(nsIDOMNode *aNode, { nsString tag; element->GetTagName(tag); - if (propName.Equals(tag)) + if (propName.EqualsIgnoreCase(tag)) { PRBool found = PR_FALSE; if (aAttribute) @@ -613,7 +612,7 @@ void nsTextEditor::IsTextPropertySetByContent(nsIDOMNode *aNode, if (!aValue) { found = PR_TRUE; } - else if (aValue->Equals(value)) { + else if (aValue->EqualsIgnoreCase(value)) { found = PR_TRUE; } 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); if (NS_SUCCEEDED(result)) { // must get child offset AFTER delete of aNewParentNode! - result = nsIEditorSupport::GetChildOffset(aNode, parentNode, offsetInParent); + result = GetChildOffset(aNode, parentNode, offsetInParent); if (NS_SUCCEEDED(result)) { result = nsEditor::InsertNode(aNewParentNode, parentNode, offsetInParent); @@ -1278,298 +1277,6 @@ NS_IMETHODIMP nsTextEditor::MoveContentOfNodeIntoNewParent(nsIDOMNode *aNode, 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; - nsCOMPtrnodeAsChar; - nodeAsChar = do_QueryInterface(aNode); - if (nodeAsChar) { - nodeAsChar->GetLength(&aCount); - } - else - { - PRBool hasChildNodes; - aNode->HasChildNodes(&hasChildNodes); - if (PR_TRUE==hasChildNodes) - { - nsCOMPtrnodeList; - 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; - nsCOMPtrelement; - 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; - nsCOMPtrparent; - nsCOMPtrtemp; - 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; - - nsCOMPtrsibling; - result = aChild->GetPreviousSibling(getter_AddRefs(sibling)); - while ((NS_SUCCEEDED(result)) && sibling) - { - PRBool isInline; - IsNodeInline(sibling, isInline); - if (PR_FALSE==isInline) - { - nsCOMPtrnodeAsText = 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) - { - nsCOMPtrnodeAsText = 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; - nsCOMPtriter; - result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull, - kIContentIteratorIID, getter_AddRefs(iter)); - if ((NS_SUCCEEDED(result)) && iter) - { - nsCOMPtr lastRange; - iter->Init(aRange); - nsCOMPtr currentContent; - iter->CurrentNode(getter_AddRefs(currentContent)); - while (NS_COMFALSE == iter->IsDone()) - { - nsCOMPtrcurrentNode = 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) - { - nsCOMPtrleftNode; - nsCOMPtrrightNode; - 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 lastStartNode; - nsCOMPtr 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 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 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; } - - nsCOMPtriter; - 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) - { - nsCOMPtrstartContent; - startContent = do_QueryInterface(aStartNode); - nsCOMPtrendContent; - endContent = do_QueryInterface(aEndNode); - if (startContent && endContent) - { - iter->Init(aRange); - nsCOMPtr content; - iter->CurrentNode(getter_AddRefs(content)); - while (NS_COMFALSE == iter->IsDone()) - { - if ((content.get() != startContent.get()) && - (content.get() != endContent.get())) - { - nsCOMPtrcurrentNode; - currentNode = do_QueryInterface(content); - PRBool isInline=PR_FALSE; - IsNodeInline(currentNode, isInline); - if (PR_FALSE==isInline) - { - nsCOMPtrnodeAsText; - 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 */ NS_IMETHODIMP nsTextEditor::SetTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode, @@ -1641,7 +1348,7 @@ NS_IMETHODIMP nsTextEditor::MoveContiguousContentIntoNewParent(nsIDOMNode *aSta { PRInt32 offsetInParent; if (newLeftNode) { - result = nsIEditorSupport::GetChildOffset(newLeftNode, aGrandParentNode, offsetInParent); + result = GetChildOffset(newLeftNode, aGrandParentNode, offsetInParent); } else { 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 (NS_SUCCEEDED(result)) { - if (PR_FALSE==tag.Equals(aPropName->GetUnicode())) + if (PR_FALSE==tag.EqualsIgnoreCase(aPropName->GetUnicode())) { PRInt32 offsetInParent; - result = nsIEditorSupport::GetChildOffset(newMiddleNode, parent, offsetInParent); + result = GetChildOffset(newMiddleNode, parent, offsetInParent); if (NS_SUCCEEDED(result)) { if (0!=offsetInParent) { @@ -1947,7 +1654,7 @@ NS_IMETHODIMP nsTextEditor::RemoveTextPropertiesForNode(nsIDOMNode *aNode, { if (gNoisy) { printf("* this is the style node\n");} PRInt32 offsetInParent; - result = nsIEditorSupport::GetChildOffset(newMiddleNode, parent, offsetInParent); + result = GetChildOffset(newMiddleNode, parent, offsetInParent); if (NS_SUCCEEDED(result)) { nsCOMPtrchildNodes; @@ -1980,7 +1687,7 @@ NS_IMETHODIMP nsTextEditor::RemoveTextPropertiesForNode(nsIDOMNode *aNode, { // promote the selection to the grandparent // first, determine the child's position in it's parent PRInt32 childPositionInParent; - nsIEditorSupport::GetChildOffset(newMiddleNode, parent, childPositionInParent); + GetChildOffset(newMiddleNode, parent, childPositionInParent); // compare childPositionInParent to the number of children in parent PRUint32 count=0; nsCOMPtrchildNodes; @@ -2004,7 +1711,7 @@ NS_IMETHODIMP nsTextEditor::RemoveTextPropertiesForNode(nsIDOMNode *aNode, if (NS_SUCCEEDED(result)) { PRInt32 position; - result = nsIEditorSupport::GetChildOffset(parent, grandParent, position); + result = GetChildOffset(parent, grandParent, position); if (NS_SUCCEEDED(result)) { if (PR_TRUE==insertAfter) @@ -2242,7 +1949,7 @@ nsTextEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStar { nsString tag; element->GetTagName(tag); - if (propName.Equals(tag)) + if (propName.EqualsIgnoreCase(tag)) { if (-1==nodeList.IndexOf(content.get())) { nodeList.AppendElement((void *)(content.get())); @@ -2272,7 +1979,7 @@ nsTextEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStar if (NS_SUCCEEDED(result) && parentNode) { PRInt32 position; - result = nsIEditorSupport::GetChildOffset(styleNode, parentNode, position); + result = GetChildOffset(styleNode, parentNode, position); if (NS_SUCCEEDED(result)) { nsCOMPtrpreviousSiblingNode; diff --git a/mozilla/editor/base/nsTextEditor.h b/mozilla/editor/base/nsTextEditor.h index 85224f4a0ac..6153fb03ce2 100644 --- a/mozilla/editor/base/nsTextEditor.h +++ b/mozilla/editor/base/nsTextEditor.h @@ -145,39 +145,6 @@ protected: const nsString *aAttributes, 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) * into aNewParentNode, splitting aNode as necessary to maintain the relative * position of all leaf content. diff --git a/mozilla/editor/libeditor/base/CreateElementTxn.cpp b/mozilla/editor/libeditor/base/CreateElementTxn.cpp index 5bdd71f2797..25cd713c707 100644 --- a/mozilla/editor/libeditor/base/CreateElementTxn.cpp +++ b/mozilla/editor/libeditor/base/CreateElementTxn.cpp @@ -17,12 +17,12 @@ */ #include "CreateElementTxn.h" +#include "nsEditor.h" #include "nsIDOMDocument.h" #include "nsIDOMNodeList.h" #include "nsIDOMSelection.h" #include "nsIDOMText.h" #include "nsIDOMElement.h" -#include "nsIEditorSupport.h" #ifdef NS_DEBUG static PRBool gNoisy = PR_FALSE; @@ -125,7 +125,7 @@ NS_IMETHODIMP CreateElementTxn::Do(void) nsresult selectionResult = mEditor->GetSelection(getter_AddRefs(selection)); if (NS_SUCCEEDED(selectionResult) && selection) { PRInt32 offset=0; - nsIEditorSupport::GetChildOffset(mNewNode, mParent, offset); + nsEditor::GetChildOffset(mNewNode, mParent, offset); selectionResult = selection->Collapse(mParent, offset); 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) { PRInt32 offset=0; if (mRefNode) { - nsIEditorSupport::GetChildOffset(mRefNode, mParent, offset); + nsEditor::GetChildOffset(mRefNode, mParent, offset); } selectionResult = selection->Collapse(mParent, offset); 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)); if (NS_SUCCEEDED(result) && selection) { PRInt32 offset=0; - nsIEditorSupport::GetChildOffset(mNewNode, mParent, offset); + nsEditor::GetChildOffset(mNewNode, mParent, offset); nsresult selectionResult = selection->Collapse(mParent, offset); NS_ASSERTION((NS_SUCCEEDED(selectionResult)), "selection could not be collapsed after undo of insert."); } diff --git a/mozilla/editor/libeditor/base/JoinElementTxn.cpp b/mozilla/editor/libeditor/base/JoinElementTxn.cpp index cee9303ebad..ef9e17cb7a6 100644 --- a/mozilla/editor/libeditor/base/JoinElementTxn.cpp +++ b/mozilla/editor/libeditor/base/JoinElementTxn.cpp @@ -17,10 +17,10 @@ */ #include "JoinElementTxn.h" +#include "nsEditor.h" #include "nsIDOMNodeList.h" #include "nsIDOMCharacterData.h" #include "nsIDOMSelection.h" -#include "nsIEditorSupport.h" #ifdef NS_DEBUG static PRBool gNoisy = PR_FALSE; @@ -28,9 +28,6 @@ static PRBool gNoisy = PR_FALSE; static const PRBool gNoisy = PR_FALSE; #endif -static NS_DEFINE_IID(kIEditorSupportIID, NS_IEDITORSUPPORT_IID); - - JoinElementTxn::JoinElementTxn() : EditTxn() { @@ -84,19 +81,15 @@ NS_IMETHODIMP JoinElementTxn::Do(void) leftNodeAsText->GetLength(&mOffset); } } - nsCOMPtr editor; - result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); - if (NS_SUCCEEDED(result) && editor) { - result = editor->JoinNodesImpl(mRightNode, mLeftNode, mParent, PR_FALSE); - if (NS_SUCCEEDED(result)) + result = nsEditor::JoinNodesImpl(mRightNode, mLeftNode, mParent, PR_FALSE); + if (NS_SUCCEEDED(result)) + { + if (gNoisy) { printf(" left node = %p removed\n", mLeftNode.get()); } + nsCOMPtrselection; + mEditor->GetSelection(getter_AddRefs(selection)); + if (selection) { - if (gNoisy) { printf(" left node = %p removed\n", mLeftNode.get()); } - nsCOMPtrselection; - mEditor->GetSelection(getter_AddRefs(selection)); - if (selection) - { - selection->Collapse(mRightNode, mOffset); - } + selection->Collapse(mRightNode, mOffset); } } } diff --git a/mozilla/editor/libeditor/base/SplitElementTxn.cpp b/mozilla/editor/libeditor/base/SplitElementTxn.cpp index b776a8f0630..bbc81ece56d 100644 --- a/mozilla/editor/libeditor/base/SplitElementTxn.cpp +++ b/mozilla/editor/libeditor/base/SplitElementTxn.cpp @@ -17,10 +17,10 @@ */ #include "SplitElementTxn.h" +#include "nsEditor.h" #include "nsIDOMNode.h" #include "nsIDOMSelection.h" #include "nsIDOMCharacterData.h" -#include "nsIEditorSupport.h" #ifdef NS_DEBUG static PRBool gNoisy = PR_FALSE; @@ -28,7 +28,6 @@ static PRBool gNoisy = PR_FALSE; static const PRBool gNoisy = PR_FALSE; #endif -static NS_DEFINE_IID(kIEditorSupportIID, NS_IEDITORSUPPORT_IID); // note that aEditor is not refcounted SplitElementTxn::SplitElementTxn() @@ -69,19 +68,14 @@ NS_IMETHODIMP SplitElementTxn::Do(void) // insert the new node if ((NS_SUCCEEDED(result)) && (mParent)) { - nsCOMPtr editor; - result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); - if (NS_SUCCEEDED(result) && editor) + result = nsEditor::SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent); + if (NS_SUCCEEDED(result) && mNewLeftNode) { - result = editor->SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent); - if (NS_SUCCEEDED(result) && mNewLeftNode) + nsCOMPtrselection; + mEditor->GetSelection(getter_AddRefs(selection)); + if (selection) { - nsCOMPtrselection; - mEditor->GetSelection(getter_AddRefs(selection)); - if (selection) - { - selection->Collapse(mNewLeftNode, mOffset); - } + selection->Collapse(mNewLeftNode, mOffset); } } else { @@ -105,25 +99,20 @@ NS_IMETHODIMP SplitElementTxn::Undo(void) // this assumes Do inserted the new node in front of the prior existing node nsresult result; - nsCOMPtr editor; - result = mEditor->QueryInterface(kIEditorSupportIID, getter_AddRefs(editor)); - if (NS_SUCCEEDED(result) && editor) + result = nsEditor::JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent, PR_FALSE); + if (gNoisy) + { + 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("** after join left child node %p into right node %p\n", mNewLeftNode.get(), mExistingRightNode.get()); - if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG - } - if (NS_SUCCEEDED(result)) + if (gNoisy) { printf(" left node = %p removed\n", mNewLeftNode.get()); } + nsCOMPtrselection; + mEditor->GetSelection(getter_AddRefs(selection)); + if (selection) { - if (gNoisy) { printf(" left node = %p removed\n", mNewLeftNode.get()); } - nsCOMPtrselection; - mEditor->GetSelection(getter_AddRefs(selection)); - if (selection) - { - selection->Collapse(mExistingRightNode, mOffset); - } + selection->Collapse(mExistingRightNode, mOffset); } } else { diff --git a/mozilla/editor/libeditor/base/nsEditor.cpp b/mozilla/editor/libeditor/base/nsEditor.cpp index 77879a104a8..70baa157ba1 100644 --- a/mozilla/editor/libeditor/base/nsEditor.cpp +++ b/mozilla/editor/libeditor/base/nsEditor.cpp @@ -19,6 +19,7 @@ #include "nsIDOMDocument.h" #include "nsEditor.h" +#include "nsIEditProperty.h" // to be removed XXX #include "nsIDOMText.h" #include "nsIDOMElement.h" #include "nsIDOMAttr.h" @@ -41,6 +42,7 @@ #include "nsIEnumerator.h" #include "nsIAtom.h" #include "nsVoidArray.h" +#include "nsISupportsArray.h" #include "nsICaret.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(kIDOMSelectionIID, NS_IDOMSELECTION_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(kIDocumentIID, NS_IDOCUMENT_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(kIHTMLEditFactoryIID, NS_IHTMLEDITORFACTORY_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); @@ -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_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 -static PRBool gNoisy = PR_FALSE; +static PRBool gNoisy = PR_TRUE; #else static const PRBool gNoisy = PR_FALSE; #endif @@ -324,7 +329,7 @@ nsEditor::~nsEditor() -//BEGIN nsIEditor interface implementations +// BEGIN nsEditor core implementation NS_IMPL_ADDREF(nsEditor) @@ -351,11 +356,6 @@ 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; } @@ -665,109 +665,6 @@ nsEditor::InsertBreak() //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 node; - nsCOMPtr 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 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 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 answer; - - aNode->GetNodeType(&mType); - - if (nsIDOMNode::ELEMENT_NODE == mType) { - if (NS_SUCCEEDED(aNode->HasChildNodes(&mCNodes)) && PR_TRUE == mCNodes) - { - nsCOMPtr node1; - nsCOMPtr 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 nsEditor::Do(nsITransaction *aTxn) @@ -1510,7 +1407,7 @@ NS_IMETHODIMP nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtrGetParentNode(getter_AddRefs(parentSelectedNode)); selectedParentNodeAsText->GetLength(&selectedNodeContentCount); - nsIEditorSupport::GetChildOffset(selectedNode, parentSelectedNode, indexOfTextNodeInParent); + GetChildOffset(selectedNode, parentSelectedNode, indexOfTextNodeInParent); if ((offsetOfSelectedNode!=0) && (((PRUint32)offsetOfSelectedNode)!=selectedNodeContentCount)) { @@ -1518,7 +1415,7 @@ NS_IMETHODIMP nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtrGetPreviousSibling(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 parent(do_QueryInterface(aCurrentNode)); - do { - nsCOMPtr 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 parent(do_QueryInterface(aCurrentNode)); - do { - nsCOMPtr 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 resultNode(do_QueryInterface(aCurrentNode)); - PRBool hasChildren; - resultNode->HasChildNodes(&hasChildren); - while ((NS_SUCCEEDED(result)) && (PR_TRUE==hasChildren)) - { - nsCOMPtr 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 resultNode(do_QueryInterface(aCurrentNode)); - PRBool hasChildren; - resultNode->HasChildNodes(&hasChildren); - while ((NS_SUCCEEDED(result)) && (PR_TRUE==hasChildren)) - { - nsCOMPtr temp(resultNode); - temp->GetFirstChild(getter_AddRefs(resultNode)); - resultNode->HasChildNodes(&hasChildren); - } - - if (NS_SUCCEEDED(result)) { - *aResultNode = resultNode; - NS_ADDREF(*aResultNode); - } - return result; -} NS_IMETHODIMP nsEditor::SplitNode(nsIDOMNode * aNode, @@ -2037,7 +1832,12 @@ NS_IMETHODIMP nsEditor::CreateTxnForJoinNode(nsIDOMNode *aLeftNode, return result; } -NS_IMETHODIMP + +// END nsEditor core implementation + +// BEGIN nsEditor public static helper methods + +nsresult nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode, PRInt32 aOffset, nsIDOMNode* aNewLeftNode, @@ -2113,7 +1913,7 @@ nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode, return result; } -NS_IMETHODIMP +nsresult nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep, nsIDOMNode * aNodeToJoin, nsIDOMNode * aParent, @@ -2203,7 +2003,8 @@ nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep, 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"); nsresult result = NS_ERROR_NULL_POINTER; @@ -2236,8 +2037,478 @@ nsresult nsIEditorSupport::GetChildOffset(nsIDOMNode *aChild, nsIDOMNode *aParen 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; + nsCOMPtrnodeAsChar; + nodeAsChar = do_QueryInterface(aNode); + if (nodeAsChar) { + nodeAsChar->GetLength(&aCount); + } + else + { + PRBool hasChildNodes; + aNode->HasChildNodes(&hasChildNodes); + if (PR_TRUE==hasChildNodes) + { + nsCOMPtrnodeList; + 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; + nsCOMPtrelement; + 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; + nsCOMPtrparent; + nsCOMPtrtemp; + 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; + + nsCOMPtrsibling; + result = aChild->GetPreviousSibling(getter_AddRefs(sibling)); + while ((NS_SUCCEEDED(result)) && sibling) + { + PRBool isInline; + IsNodeInline(sibling, isInline); + if (PR_FALSE==isInline) + { + nsCOMPtrnodeAsText = 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) + { + nsCOMPtrnodeAsText = 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; + nsCOMPtriter; + result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull, + kIContentIteratorIID, getter_AddRefs(iter)); + if ((NS_SUCCEEDED(result)) && iter) + { + nsCOMPtr lastRange; + iter->Init(aRange); + nsCOMPtr currentContent; + iter->CurrentNode(getter_AddRefs(currentContent)); + while (NS_COMFALSE == iter->IsDone()) + { + nsCOMPtrcurrentNode = do_QueryInterface(currentContent); + if (currentNode) + { + nsCOMPtr currentContentTag; + currentContent->GetTag(*getter_AddRefs(currentContentTag)); + //
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) + { + nsCOMPtrleftNode; + nsCOMPtrrightNode; + 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 lastStartNode; + nsCOMPtr 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 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 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; } + + nsCOMPtriter; + 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) + { + nsCOMPtrstartContent; + startContent = do_QueryInterface(aStartNode); + nsCOMPtrendContent; + endContent = do_QueryInterface(aEndNode); + if (startContent && endContent) + { + iter->Init(aRange); + nsCOMPtr content; + iter->CurrentNode(getter_AddRefs(content)); + while (NS_COMFALSE == iter->IsDone()) + { + if ((content.get() != startContent.get()) && + (content.get() != endContent.get())) + { + nsCOMPtrcurrentNode; + currentNode = do_QueryInterface(content); + PRBool isInline=PR_FALSE; + IsNodeInline(currentNode, isInline); + if (PR_FALSE==isInline) + { + nsCOMPtrnodeAsText; + 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 parent(do_QueryInterface(aCurrentNode)); + do { + nsCOMPtr 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 parent(do_QueryInterface(aCurrentNode)); + do { + nsCOMPtr 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 resultNode(do_QueryInterface(aCurrentNode)); + PRBool hasChildren; + resultNode->HasChildNodes(&hasChildren); + while ((NS_SUCCEEDED(result)) && (PR_TRUE==hasChildren)) + { + nsCOMPtr 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 resultNode(do_QueryInterface(aCurrentNode)); + PRBool hasChildren; + resultNode->HasChildNodes(&hasChildren); + while ((NS_SUCCEEDED(result)) && (PR_TRUE==hasChildren)) + { + nsCOMPtr 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) +{ + nsCOMPtrelement; + 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; + nsCOMPtrelement; + 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 + { + nsCOMPtrtext; + 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 nodeAsContent(aCellNode); - if (nodeAsContent) - { // get the frame from the content interface - nsISupports *layoutObject=nsnull; // frames are not ref counted, so don't use an nsCOMPtr - result = aPresShell->GetLayoutObjectFor(nodeAsContent, &layoutObject); - if ((NS_SUCCEEDED(result)) && (nsnull!=layoutObject)) - { // get the table cell interface from the frame - nsITableCellLayout *cellLayoutObject=nsnull; // again, frames are not ref-counted - result = layoutObject->QueryInterface(nsITableCellLayout::GetIID(), (void**)(&cellLayoutObject)); - if ((NS_SUCCEEDED(result)) && (nsnull!=cellLayoutObject)) - { // get the index - result = cellLayoutObject->GetColIndex(aCellIndex); - } + nsresult result=NS_OK; + + if (!aStartNode) + return NS_ERROR_NULL_POINTER; + if (!aResult) + return NS_ERROR_NULL_POINTER; + + nsCOMPtr element; + *aResult = nsnull; + nsCOMPtr childNode; + result = aStartNode->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 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 answer; + + aNode->GetNodeType(&mType); + + if (nsIDOMNode::ELEMENT_NODE == mType) { + if (NS_SUCCEEDED(aNode->HasChildNodes(&mCNodes)) && PR_TRUE == mCNodes) + { + nsCOMPtr node1; + nsCOMPtr 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 { - result = NS_ERROR_NULL_POINTER; + else if (nsIDOMNode::TEXT_NODE == mType) { + 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) { @@ -2601,3 +2926,4 @@ nsEditor::SetPreeditText(const nsString& aStringToInsert) EndTransaction(); return result; } + diff --git a/mozilla/editor/libeditor/base/nsEditor.h b/mozilla/editor/libeditor/base/nsEditor.h index acd0fdae1bf..86d42bbfb37 100644 --- a/mozilla/editor/libeditor/base/nsEditor.h +++ b/mozilla/editor/libeditor/base/nsEditor.h @@ -21,7 +21,6 @@ #include "prmon.h" #include "nsIEditor.h" -#include "nsIEditorSupport.h" #include "nsIContextLoader.h" #include "nsIDOMDocument.h" #include "nsIDOMEventListener.h" @@ -46,6 +45,7 @@ class SplitElementTxn; class JoinElementTxn; class EditAggregateTxn; class nsVoidArray; +class nsISupportsArray; //This is the monitor for the editor. PRMonitor *getEditorMonitor(); @@ -56,7 +56,7 @@ PRMonitor *getEditorMonitor(); * 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, public nsIEditorSupport +class nsEditor : public nsIEditor { private: nsIPresShell *mPresShell; @@ -75,6 +75,10 @@ protected: nsIDOMDocument * mDoc; public: + + const static char* nsEditor::kMOZEditorBogusNodeAttr; + const static char* nsEditor::kMOZEditorBogusNodeValue; + /** The default constructor. This should suffice. the setting of the interfaces is done * after the construction of the editor class. */ @@ -186,32 +190,6 @@ public: /*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*/ protected: /** create a transaction for setting aAttribute to aValue on aElement @@ -278,28 +256,10 @@ protected: PRUint32 aOffset, SplitElementTxn **aTxn); - NS_IMETHOD SplitNodeImpl(nsIDOMNode * aExistingRightNode, - PRInt32 aOffset, - nsIDOMNode * aNewLeftNode, - nsIDOMNode * aParent); - NS_IMETHOD CreateTxnForJoinNode(nsIDOMNode *aLeftNode, nsIDOMNode *aRightNode, 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 * Used by all methods that need to delete current selection, * then insert something new to replace it @@ -321,11 +281,152 @@ protected: // of an error in Gecko which is not rendering the // document after a change via the DOM - gpk 2/13/99 void HACKForceRedraw(void); + PRBool mIMEFirstTransaction; - NS_IMETHOD DeleteSelectionAndPrepareToCreateNode(nsCOMPtr &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. + *
tags separate block content sections. So the HTML markup: + *
+    *      

text1
text2text3

+ *
+ * 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); + }; diff --git a/mozilla/editor/libeditor/base/nsIEditProperty.h b/mozilla/editor/libeditor/base/nsIEditProperty.h index b67f21575d1..e969c66a89d 100644 --- a/mozilla/editor/libeditor/base/nsIEditProperty.h +++ b/mozilla/editor/libeditor/base/nsIEditProperty.h @@ -73,6 +73,7 @@ SUP places text in superscript style // block tags static nsIAtom *blockquote; + static nsIAtom *br; static nsIAtom *h1; static nsIAtom *h2; diff --git a/mozilla/editor/libeditor/html/nsEditProperty.cpp b/mozilla/editor/libeditor/html/nsEditProperty.cpp index 13068ce4335..f19e50f4902 100644 --- a/mozilla/editor/libeditor/html/nsEditProperty.cpp +++ b/mozilla/editor/libeditor/html/nsEditProperty.cpp @@ -43,6 +43,7 @@ nsIAtom * nsIEditProperty::tt; nsIAtom * nsIEditProperty::u; // block tags nsIAtom * nsIEditProperty::blockquote; +nsIAtom * nsIEditProperty::br; nsIAtom * nsIEditProperty::h1; nsIAtom * nsIEditProperty::h2; // properties @@ -56,28 +57,29 @@ void nsEditProperty::InstanceInit() { // tags - nsIEditProperty::a = NS_NewAtom("A"); - nsIEditProperty::b = NS_NewAtom("B"); - nsIEditProperty::big = NS_NewAtom("BIG"); - nsIEditProperty::font = NS_NewAtom("FONT"); - nsIEditProperty::i = NS_NewAtom("I"); - nsIEditProperty::span = NS_NewAtom("SPAN"); - nsIEditProperty::small =NS_NewAtom("SMALL"); - nsIEditProperty::strike=NS_NewAtom("STRIKE"); - nsIEditProperty::sub = NS_NewAtom("SUB"); - nsIEditProperty::sup = NS_NewAtom("SUP"); - nsIEditProperty::tt = NS_NewAtom("TT"); - nsIEditProperty::u = NS_NewAtom("U"); + nsIEditProperty::a = NS_NewAtom("a"); + nsIEditProperty::b = NS_NewAtom("b"); + nsIEditProperty::big = NS_NewAtom("big"); + nsIEditProperty::font = NS_NewAtom("font"); + nsIEditProperty::i = NS_NewAtom("i"); + nsIEditProperty::span = NS_NewAtom("span"); + nsIEditProperty::small =NS_NewAtom("small"); + nsIEditProperty::strike=NS_NewAtom("strike"); + nsIEditProperty::sub = NS_NewAtom("sub"); + nsIEditProperty::sup = NS_NewAtom("sup"); + nsIEditProperty::tt = NS_NewAtom("tt"); + nsIEditProperty::u = NS_NewAtom("u"); // tags - nsIEditProperty::blockquote = NS_NewAtom("BLOCKQUOTE"); - nsIEditProperty::h1 = NS_NewAtom("H1"); - nsIEditProperty::h2 = NS_NewAtom("H2"); + nsIEditProperty::blockquote = NS_NewAtom("blockquote"); + nsIEditProperty::br = NS_NewAtom("br"); + nsIEditProperty::h1 = NS_NewAtom("h1"); + nsIEditProperty::h2 = NS_NewAtom("h2"); // properties - nsIEditProperty::color= NS_NewAtom("COLOR"); - nsIEditProperty::face = NS_NewAtom("FACE"); - nsIEditProperty::size = NS_NewAtom("SIZE"); + nsIEditProperty::color= NS_NewAtom("color"); + nsIEditProperty::face = NS_NewAtom("face"); + nsIEditProperty::size = NS_NewAtom("size"); // special - nsIEditProperty::allProperties = new nsString("moz_AllProperties"); + nsIEditProperty::allProperties = new nsString("moz_allproperties"); } void @@ -98,6 +100,7 @@ nsEditProperty::InstanceShutdown() NS_IF_RELEASE(nsIEditProperty::u); // tags NS_IF_RELEASE(nsIEditProperty::blockquote); + NS_IF_RELEASE(nsIEditProperty::br); NS_IF_RELEASE(nsIEditProperty::h1); NS_IF_RELEASE(nsIEditProperty::h2); // properties diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp index 20249dd4c6a..22ce3578337 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp @@ -40,7 +40,6 @@ #include "nsIComponentManager.h" #include "nsIServiceManager.h" -#include "nsITableCellLayout.h" //For GetColIndexForCell 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); #ifdef NS_DEBUG -static PRBool gNoisy = PR_FALSE; +static PRBool gNoisy = PR_TRUE; #else static const PRBool gNoisy = PR_FALSE; #endif @@ -205,7 +204,7 @@ NS_IMETHODIMP nsHTMLEditor::InsertBreak() if (-1==offsetInParent) { nextNode->GetParentNode(getter_AddRefs(parent)); - result = nsIEditorSupport::GetChildOffset(nextNode, parent, offsetInParent); + result = GetChildOffset(nextNode, parent, offsetInParent); if (NS_SUCCEEDED(result)) { 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)) { nsCOMPtr 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 - nsISupportsArray *subRanges; - result = NS_NewISupportsArray(&subRanges); - if ((NS_SUCCEEDED(result)) && subRanges) + nsISupportsArray *blockSections; + result = NS_NewISupportsArray(&blockSections); + if ((NS_SUCCEEDED(result)) && blockSections) { - result = GetBlockRanges(range, subRanges); + result = GetBlockSectionsForRange(range, blockSections); if (NS_SUCCEEDED(result)) { nsIDOMRange *subRange; - subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); + subRange = (nsIDOMRange *)(blockSections->ElementAt(0)); while (subRange && (NS_SUCCEEDED(result))) { nsCOMPtrstartParent; @@ -418,17 +417,19 @@ nsHTMLEditor::GetParagraphStyle(nsStringArray *aTagList) { nsAutoString 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); } } } NS_RELEASE(subRange); - subRanges->RemoveElementAt(0); - subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); + blockSections->RemoveElementAt(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)) { nsCOMPtr 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 result = ReParentContentOfRange(range, aParentTag, eInsertParent); } @@ -510,47 +511,30 @@ nsHTMLEditor::ReplaceBlockParent(nsString& aParentTag) if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) { nsCOMPtr 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 result = ReParentContentOfRange(range, aParentTag, eReplaceParent); } } 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 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 nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode, nsString &aParentTag, BlockTransformationType aTransformation) { 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 nsCOMPtrblockParentElement; nsCOMPtrnodeToReParent; // 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 // XXX: how to you know it's an insertion point??? PRInt32 offsetInParent=0; - result = nsIEditorSupport::GetChildOffset(nodeToReParent, blockParentNode, offsetInParent); + result = GetChildOffset(nodeToReParent, blockParentNode, offsetInParent); NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset"); // otherwise, just create the block parent at the selection result = nsTextEditor::CreateNode(aParentTag, blockParentNode, offsetInParent, @@ -654,10 +638,14 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, nsString &aParentTag, nsIDOMNode *aBlockParentNode, nsString &aBlockParentTag, - BlockTransformationType aTranformation, + BlockTransformationType aTransformation, nsIDOMNode **aNewParentNode) { if (!aNode || !aBlockParentNode || !aNewParentNode) { return NS_ERROR_NULL_POINTER; } + nsCOMPtr blockParentNode = do_QueryInterface(aBlockParentNode); + PRBool removeBlockParent = PR_FALSE; + PRBool removeBreakBefore = PR_FALSE; + PRBool removeBreakAfter = PR_FALSE; nsCOMPtrancestor; nsresult result = aNode->GetParentNode(getter_AddRefs(ancestor)); nsCOMPtrpreviousAncestor = do_QueryInterface(aNode); @@ -675,46 +663,87 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, } // now, previousAncestor is the node we are operating on nsCOMPtrleftNode, rightNode; - result = GetBlockDelimitedContent(previousAncestor, - getter_AddRefs(leftNode), - getter_AddRefs(rightNode)); + result = GetBlockSection(previousAncestor, + getter_AddRefs(leftNode), + getter_AddRefs(rightNode)); if ((NS_SUCCEEDED(result)) && leftNode && rightNode) { - PRInt32 offsetInParent=0; - if (eInsertParent==aTranformation) + // determine some state for managing
s around the new block + 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 + nsCOMPtrblockParentElement = 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"); - result = nsTextEditor::CreateNode(aParentTag, aBlockParentNode, offsetInParent, aNewParentNode); - if (gNoisy) { printf("created a node in aBlockParentNode at offset %d\n", offsetInParent); } + result = nsTextEditor::CreateNode(aParentTag, blockParentNode, offsetInParent, aNewParentNode); + if (gNoisy) { printf("created a node in blockParentNode at offset %d\n", offsetInParent); } } else { nsCOMPtr grandParent; - result = aBlockParentNode->GetParentNode(getter_AddRefs(grandParent)); + result = blockParentNode->GetParentNode(getter_AddRefs(grandParent)); if ((NS_SUCCEEDED(result)) && grandParent) { nsCOMPtrfirstChildNode, lastChildNode; - aBlockParentNode->GetFirstChild(getter_AddRefs(firstChildNode)); - aBlockParentNode->GetLastChild(getter_AddRefs(lastChildNode)); + blockParentNode->GetFirstChild(getter_AddRefs(firstChildNode)); + blockParentNode->GetLastChild(getter_AddRefs(lastChildNode)); 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"); result = nsTextEditor::CreateNode(aParentTag, grandParent, offsetInParent, aNewParentNode); if (gNoisy) { printf("created a node in grandParent at offset %d\n", offsetInParent); } } else { - result = nsIEditorSupport::GetChildOffset(leftNode, aBlockParentNode, offsetInParent); + // We're in the case where the content of blockParentNode is separated by
's, + // creating multiple block content ranges. + // Split blockParentNode around the blockContent + if (gNoisy) { printf("splitting a node because of
s\n"); } + nsCOMPtr 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"); - result = nsTextEditor::CreateNode(aParentTag, aBlockParentNode, offsetInParent, aNewParentNode); - if (gNoisy) { printf("created a node in aBlockParentNode at offset %d\n", offsetInParent); } + result = nsTextEditor::CreateNode(aParentTag, blockParentNode, offsetInParent, aNewParentNode); + 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) - { // move all the children/contents of aBlockParentNode to aNewParentNode + { // move all the children/contents of blockParentNode to aNewParentNode nsCOMPtrchildNode = do_QueryInterface(rightNode); nsCOMPtrpreviousSiblingNode; while (NS_SUCCEEDED(result) && childNode) @@ -737,6 +766,73 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, childNode = do_QueryInterface(previousSiblingNode); } // end while loop } + // clean up the surrounding content to maintain vertical whitespace + if (NS_SUCCEEDED(result)) + { + // if the prior node is a
and we did something to change vertical whitespacing, delete the
+ nsCOMPtr brNode; + result = GetPriorNode(leftNode, getter_AddRefs(brNode)); + if (NS_SUCCEEDED(result) && brNode) + { + nsCOMPtr brContent = do_QueryInterface(brNode); + if (brContent) + { + nsCOMPtr brContentTag; + brContent->GetTag(*getter_AddRefs(brContentTag)); + if (nsIEditProperty::br==brContentTag) { + result = DeleteNode(brNode); + } + } + } + + // if the next node is a
and we did something to change vertical whitespacing, delete the
+ if (NS_SUCCEEDED(result)) + { + result = GetNextNode(rightNode, getter_AddRefs(brNode)); + if (NS_SUCCEEDED(result) && brNode) + { + nsCOMPtr brContent = do_QueryInterface(brNode); + if (brContent) + { + nsCOMPtr 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 childNodes; + result = blockParentNode->GetChildNodes(getter_AddRefs(childNodes)); + if ((NS_SUCCEEDED(result)) && (childNodes)) + { + nsCOMPtrgrandParent; + 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 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; } @@ -748,29 +844,30 @@ nsHTMLEditor::ReParentContentOfRange(nsIDOMRange *aRange, { if (!aRange) { return NS_ERROR_NULL_POINTER; } nsresult result; - nsISupportsArray *subRanges; - result = NS_NewISupportsArray(&subRanges); - if ((NS_SUCCEEDED(result)) && subRanges) + nsISupportsArray *blockSections; + result = NS_NewISupportsArray(&blockSections); + if ((NS_SUCCEEDED(result)) && blockSections) { - result = GetBlockRanges(aRange, subRanges); + result = GetBlockSectionsForRange(aRange, blockSections); if (NS_SUCCEEDED(result)) { nsIDOMRange *subRange; - subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); + subRange = (nsIDOMRange *)(blockSections->ElementAt(0)); while (subRange && (NS_SUCCEEDED(result))) { nsCOMPtrstartParent; result = subRange->GetStartParent(getter_AddRefs(startParent)); if (NS_SUCCEEDED(result) && startParent) { + if (gNoisy) { printf("ReParentContentOfRange calling ReParentContentOfNode\n"); } result = ReParentContentOfNode(startParent, aParentTag, aTranformation); } NS_RELEASE(subRange); - subRanges->RemoveElementAt(0); - subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); + blockSections->RemoveElementAt(0); + subRange = (nsIDOMRange *)(blockSections->ElementAt(0)); } } - NS_RELEASE(subRanges); + NS_RELEASE(blockSections); } return result; } @@ -793,10 +890,10 @@ nsHTMLEditor::CanContainBlock(nsString &aBlockChild, nsString &aBlockParent, PRB } NS_IMETHODIMP -nsHTMLEditor::RemoveBlockParent() +nsHTMLEditor::RemoveParagraphStyle() { if (gNoisy) { - printf("---------- nsHTMLEditor::RemoveBlockParent ----------\n"); + printf("---------- nsHTMLEditor::RemoveParagraphStyle ----------\n"); } nsresult result=NS_ERROR_NOT_INITIALIZED; @@ -815,65 +912,7 @@ nsHTMLEditor::RemoveBlockParent() if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) { nsCOMPtr range( do_QueryInterface(currentItem) ); - nsCOMPtrcommonParent; - result = range->GetCommonParent(getter_AddRefs(commonParent)); - if ((NS_SUCCEEDED(result)) && commonParent) - { - PRInt32 startOffset, endOffset; - range->GetStartOffset(&startOffset); - range->GetEndOffset(&endOffset); - nsCOMPtr startParent; nsCOMPtr 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 - nsCOMPtrblockParentElement; - 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 childNodes; - result = blockParentElement->GetChildNodes(getter_AddRefs(childNodes)); - if ((NS_SUCCEEDED(result)) && (childNodes)) - { - nsCOMPtrgrandParent; - 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 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)); - } - } - } + result = RemoveParagraphStyleFromRange(range); } } nsEditor::EndTransaction(); @@ -881,11 +920,93 @@ nsHTMLEditor::RemoveBlockParent() 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; + nsCOMPtrstartParent; + aRange->GetStartParent(getter_AddRefs(startParent)); + nsCOMPtrblockParentElement; + 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 childNodes; + result = blockParentElement->GetChildNodes(getter_AddRefs(childNodes)); + if ((NS_SUCCEEDED(result)) && (childNodes)) + { + nsCOMPtrgrandParent; + 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 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 nsHTMLEditor::RemoveParent(const nsString &aParentTag) { if (gNoisy) { - printf("---------- nsHTMLEditor::RemoveParent %s----------\n", aParentTag); + printf("---------- nsHTMLEditor::RemoveParagraphStyle ----------\n"); } nsresult result=NS_ERROR_NOT_INITIALIZED; @@ -904,68 +1025,7 @@ nsHTMLEditor::RemoveParent(const nsString &aParentTag) if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) { nsCOMPtr range( do_QueryInterface(currentItem) ); - nsCOMPtrcommonParent; - result = range->GetCommonParent(getter_AddRefs(commonParent)); - if ((NS_SUCCEEDED(result)) && commonParent) - { - PRInt32 startOffset, endOffset; - range->GetStartOffset(&startOffset); - range->GetEndOffset(&endOffset); - nsCOMPtr startParent; nsCOMPtr 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 - nsCOMPtrparentNode; - nsCOMPtrparentElement; - 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 childNodes; - result = parentElement->GetChildNodes(getter_AddRefs(childNodes)); - if ((NS_SUCCEEDED(result)) && (childNodes)) - { - nsCOMPtrgrandParent; - 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 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)); - } - } - } + result = RemoveParentFromRange(aParentTag, range); } } nsEditor::EndTransaction(); @@ -973,6 +1033,92 @@ nsHTMLEditor::RemoveParent(const nsString &aParentTag) 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; + nsCOMPtrstartParent; + result = aRange->GetStartParent(getter_AddRefs(startParent)); + if ((NS_SUCCEEDED(result)) && startParent) + { + nsCOMPtrparentNode; + nsCOMPtrparentElement; + 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 childNodes; + result = parentElement->GetChildNodes(getter_AddRefs(childNodes)); + if ((NS_SUCCEEDED(result)) && (childNodes)) + { + nsCOMPtrgrandParent; + 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 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 nsHTMLEditor::InsertLink(nsString& aURL) @@ -1331,6 +1477,62 @@ nsHTMLEditor::InsertElement(nsIDOMElement* aElement, PRBool aDeleteSelection, ns 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) { return nsTextEditor::BeginComposition(); @@ -1344,4 +1546,4 @@ NS_IMETHODIMP nsHTMLEditor::EndComposition(void) NS_IMETHODIMP nsHTMLEditor::SetCompositionString(const nsString& aCompositionString) { return nsTextEditor::SetCompositionString(aCompositionString); -} \ No newline at end of file +} diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.h b/mozilla/editor/libeditor/html/nsHTMLEditor.h index ffe65fb6402..1ad352f8868 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.h +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.h @@ -107,7 +107,7 @@ public: NS_IMETHOD GetParagraphStyle(nsStringArray *aTagList); NS_IMETHOD AddBlockParent(nsString& aParentTag); NS_IMETHOD ReplaceBlockParent(nsString& aParentTag); - NS_IMETHOD RemoveBlockParent(); + NS_IMETHOD RemoveParagraphStyle(); NS_IMETHOD RemoveParent(const nsString &aParentTag); NS_IMETHOD InsertLink(nsString& aURL); @@ -163,8 +163,22 @@ protected: nsString &aParentTag, 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 IsRootTag(nsString &aTag, PRBool &aIsTag); + + NS_IMETHOD IsSubordinateBlock(nsString &aTag, PRBool &aIsTag); + + // EVENT LISTENERS AND COMMAND ROUTING NEEDS WORK // For now, the listners are tied to the nsTextEditor class // diff --git a/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp b/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp index 09c6ec09673..d2f59355f9b 100644 --- a/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp +++ b/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp @@ -25,6 +25,7 @@ #include "nsIDOMCharacterData.h" #include "nsIEditProperty.h" #include "nsISupportsArray.h" +#include "nsVoidArray.h" #include "nsString.h" #include "nsIStringStream.h" @@ -599,7 +600,39 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr nsCOMPtrhtmlEditor; htmlEditor = do_QueryInterface(mEditor); 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) + { + nsCOMPtrhtmlEditor; + 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; iToNewCString(); + printf("%s ", tagCString); + delete [] tagCString; + } + printf("\n"); + } } } } diff --git a/mozilla/editor/libeditor/text/nsTextEditRules.cpp b/mozilla/editor/libeditor/text/nsTextEditRules.cpp index 603cf02bf70..8251aa3ea21 100644 --- a/mozilla/editor/libeditor/text/nsTextEditRules.cpp +++ b/mozilla/editor/libeditor/text/nsTextEditRules.cpp @@ -18,6 +18,7 @@ #include "nsTextEditRules.h" #include "nsTextEditor.h" +#include "nsEditor.h" #include "PlaceholderTxn.h" #include "InsertTextTxn.h" #include "nsCOMPtr.h" @@ -31,69 +32,8 @@ #include "nsIContent.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); -/******************************************************** - * Helper Functions - ********************************************************/ - -PRBool nsTextEditRules::NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag) -{ - nsCOMPtrelement; - 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; - nsCOMPtrelement; - 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 - { - nsCOMPtrtext; - 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, nsCOMPtrparent; aNode->GetParentNode(getter_AddRefs(parent)); PRInt32 offsetInParent; - nsIEditorSupport::GetChildOffset(aNode, parent, offsetInParent); + nsEditor::GetChildOffset(aNode, parent, offsetInParent); nsAutoString tag; aTag->ToString(tag); result = mEditor->CreateNode(tag, parent, offsetInParent, aNewNode); @@ -563,7 +503,7 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection, nsresult aResul result = bodyNode->GetFirstChild(getter_AddRefs(bodyChild)); while ((NS_SUCCEEDED(result)) && bodyChild) { - if (PR_TRUE==IsEditable(bodyChild)) + if (PR_TRUE==nsEditor::IsEditable(bodyChild)) { needsBogusContent = PR_FALSE; break; @@ -599,8 +539,8 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection, nsresult aResul newPElement = do_QueryInterface(mBogusNode); if (newPElement) { - nsAutoString att(kMOZEditorBogusNodeAttr); - nsAutoString val(kMOZEditorBogusNodeValue); + nsAutoString att(nsEditor::kMOZEditorBogusNodeAttr); + nsAutoString val(nsEditor::kMOZEditorBogusNodeValue); newPElement->SetAttribute(att, val); } } @@ -706,10 +646,10 @@ nsTextEditRules:: DidUndo(nsIDOMSelection *aSelection, nsresult aResult) element = do_QueryInterface(node); if (element) { - nsAutoString att(kMOZEditorBogusNodeAttr); + nsAutoString att(nsEditor::kMOZEditorBogusNodeAttr); nsAutoString val; (void)element->GetAttribute(att, val); - if (val.Equals(kMOZEditorBogusNodeValue)) { + if (val.Equals(nsEditor::kMOZEditorBogusNodeValue)) { mBogusNode = do_QueryInterface(element); } } @@ -752,10 +692,10 @@ nsTextEditRules::DidRedo(nsIDOMSelection *aSelection, nsresult aResult) element = do_QueryInterface(node); if (element) { - nsAutoString att(kMOZEditorBogusNodeAttr); + nsAutoString att(nsEditor::kMOZEditorBogusNodeAttr); nsAutoString val; (void)element->GetAttribute(att, val); - if (val.Equals(kMOZEditorBogusNodeValue)) { + if (val.Equals(nsEditor::kMOZEditorBogusNodeValue)) { mBogusNode = do_QueryInterface(element); } } diff --git a/mozilla/editor/libeditor/text/nsTextEditRules.h b/mozilla/editor/libeditor/text/nsTextEditRules.h index 08796b0dc86..459306a7e89 100644 --- a/mozilla/editor/libeditor/text/nsTextEditRules.h +++ b/mozilla/editor/libeditor/text/nsTextEditRules.h @@ -85,8 +85,6 @@ protected: nsresult DidRedo(nsIDOMSelection *aSelection, nsresult aResult); // helper functions - static PRBool NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag); - static PRBool IsEditable(nsIDOMNode *aNode); /** insert aNode into a new style node of type aTag. * aSelection is optional. If provided, aSelection is set to (aNode, 0) diff --git a/mozilla/editor/public/nsIEditor.h b/mozilla/editor/public/nsIEditor.h index 5a11979364b..25187afee03 100644 --- a/mozilla/editor/public/nsIEditor.h +++ b/mozilla/editor/public/nsIEditor.h @@ -226,9 +226,9 @@ public: * @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. */ - NS_IMETHOD SplitNode(nsIDOMNode * aExistingRightNode, + NS_IMETHOD SplitNode(nsIDOMNode *aExistingRightNode, PRInt32 aOffset, - nsIDOMNode ** aNewLeftNode)=0; + nsIDOMNode **aNewLeftNode)=0; /** * JoinNodes() takes 2 nodes and merge their content|children. @@ -333,29 +333,28 @@ public: * What if no text is selected? * What about mixed selections? * What are the clipboard formats? - */ + */ NS_IMETHOD Cut()=0; /** copy the currently selected text, putting it into the OS clipboard * What if no text is selected? * What about mixed selections? * What are the clipboard formats? - */ + */ NS_IMETHOD Copy()=0; /** paste the text in the OS clipboard at the cursor position, replacing * the selected text (if any) - */ + */ 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; - /** 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; + /** Dumps a text representation of the content tree to standard out */ NS_IMETHOD DebugDumpContent() const =0; }; diff --git a/mozilla/editor/public/nsIHTMLEditor.h b/mozilla/editor/public/nsIHTMLEditor.h index a89b6ff62ec..40826a5b861 100644 --- a/mozilla/editor/public/nsIHTMLEditor.h +++ b/mozilla/editor/public/nsIHTMLEditor.h @@ -123,11 +123,13 @@ public: */ 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. * if aTagToRemove is null, the nearest enclosing block that - * is not a sub-document is removed. + * is not a root is removed. */ - NS_IMETHOD RemoveBlockParent()=0; NS_IMETHOD RemoveParent(const nsString &aParentTag)=0; NS_IMETHOD InsertLink(nsString& aURL)=0; diff --git a/mozilla/editor/public/nsITextEditor.h b/mozilla/editor/public/nsITextEditor.h index f6c20525585..e75f6e25810 100644 --- a/mozilla/editor/public/nsITextEditor.h +++ b/mozilla/editor/public/nsITextEditor.h @@ -27,7 +27,6 @@ #include "nsIEditor.h" #include "nscore.h" -class nsIEditorCallback; class nsISupportsArray; class nsIAtom; class nsIOutputStream;