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;