From 02dbe54c0dfd1c89cbb572c312d69eec5e997fa2 Mon Sep 17 00:00:00 2001 From: "akkana%netscape.com" Date: Thu, 5 Apr 2001 23:48:01 +0000 Subject: [PATCH] 66345: Factoring necessary for editor reorganization. sr=kin/sfraser, r=jfrancis git-svn-id: svn://10.0.0.236/trunk@91511 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/editor/base/Makefile.in | 4 +- mozilla/editor/base/PlaceholderTxn.cpp | 8 +- mozilla/editor/base/SetDocTitleTxn.cpp | 4 +- mozilla/editor/base/makefile.win | 4 +- mozilla/editor/base/nsEditor.cpp | 583 ++---------------- mozilla/editor/base/nsEditor.h | 71 +-- mozilla/editor/base/nsEditorController.cpp | 111 ---- mozilla/editor/base/nsEditorController.h | 27 +- .../editor/base/nsEditorEventListeners.cpp | 1 - mozilla/editor/base/nsEditorRegistration.cpp | 40 +- mozilla/editor/base/nsEditorShell.cpp | 176 +----- .../base/nsEditorShellMouseListener.cpp | 5 +- mozilla/editor/base/nsEditorUtils.h | 20 +- mozilla/editor/base/nsHTMLDataTransfer.cpp | 49 +- mozilla/editor/base/nsHTMLEditRules.cpp | 147 +++-- mozilla/editor/base/nsHTMLEditUtils.cpp | 140 +---- mozilla/editor/base/nsHTMLEditUtils.h | 8 - mozilla/editor/base/nsHTMLEditor.cpp | 579 ++++++++++++++++- mozilla/editor/base/nsHTMLEditor.h | 64 +- mozilla/editor/base/nsHTMLEditorStyle.cpp | 12 +- .../editor/base/nsPlaintextDataTransfer.cpp | 11 +- mozilla/editor/base/nsPlaintextEditor.cpp | 382 ++++++++++-- mozilla/editor/base/nsPlaintextEditor.h | 25 +- mozilla/editor/base/nsTableEditor.cpp | 3 +- mozilla/editor/base/nsTextEditRules.cpp | 8 +- mozilla/editor/composer/src/nsEditorShell.cpp | 176 +----- .../src/nsEditorShellMouseListener.cpp | 5 +- .../editor/libeditor/base/PlaceholderTxn.cpp | 8 +- .../editor/libeditor/base/SetDocTitleTxn.cpp | 4 +- mozilla/editor/libeditor/base/nsEditor.cpp | 583 ++---------------- mozilla/editor/libeditor/base/nsEditor.h | 71 +-- .../libeditor/base/nsEditorController.cpp | 111 ---- .../libeditor/base/nsEditorController.h | 27 +- mozilla/editor/libeditor/base/nsEditorUtils.h | 20 +- .../libeditor/build/nsEditorRegistration.cpp | 40 +- .../libeditor/html/nsHTMLDataTransfer.cpp | 49 +- .../editor/libeditor/html/nsHTMLEditRules.cpp | 147 +++-- .../editor/libeditor/html/nsHTMLEditUtils.cpp | 140 +---- .../editor/libeditor/html/nsHTMLEditUtils.h | 8 - .../editor/libeditor/html/nsHTMLEditor.cpp | 579 ++++++++++++++++- mozilla/editor/libeditor/html/nsHTMLEditor.h | 64 +- .../libeditor/html/nsHTMLEditorStyle.cpp | 12 +- .../editor/libeditor/html/nsTableEditor.cpp | 3 +- .../libeditor/text/nsEditorEventListeners.cpp | 1 - .../text/nsPlaintextDataTransfer.cpp | 11 +- .../libeditor/text/nsPlaintextEditor.cpp | 382 ++++++++++-- .../editor/libeditor/text/nsPlaintextEditor.h | 25 +- .../editor/libeditor/text/nsTextEditRules.cpp | 8 +- mozilla/editor/public/nsIEditor.h | 8 - mozilla/editor/public/nsIEditorMailSupport.h | 54 +- mozilla/editor/public/nsIHTMLEditor.h | 8 + 51 files changed, 2433 insertions(+), 2593 deletions(-) diff --git a/mozilla/editor/base/Makefile.in b/mozilla/editor/base/Makefile.in index b9743d6a74d..2bc930c4f37 100644 --- a/mozilla/editor/base/Makefile.in +++ b/mozilla/editor/base/Makefile.in @@ -43,13 +43,15 @@ CPPSRCS = \ InsertElementTxn.cpp \ InsertTextTxn.cpp \ JoinElementTxn.cpp \ - nsComposerCommands.cpp \ nsEditorCommands.cpp \ + nsComposerCommands.cpp \ nsEditorController.cpp \ + nsComposerController.cpp \ nsEditor.cpp \ nsEditorEventListeners.cpp \ nsEditorUtils.cpp \ nsEditProperty.cpp \ + nsTextEditUtils.cpp \ nsHTMLEditUtils.cpp \ nsPlaintextDataTransfer.cpp \ nsPlaintextEditor.cpp \ diff --git a/mozilla/editor/base/PlaceholderTxn.cpp b/mozilla/editor/base/PlaceholderTxn.cpp index 68fae46d9e0..af7cee71848 100644 --- a/mozilla/editor/base/PlaceholderTxn.cpp +++ b/mozilla/editor/base/PlaceholderTxn.cpp @@ -23,7 +23,7 @@ #include "PlaceholderTxn.h" #include "nsVoidArray.h" -#include "nsHTMLEditor.h" +#include "nsEditor.h" #include "nsIPresShell.h" #include "IMETextTxn.h" @@ -178,9 +178,9 @@ NS_IMETHODIMP PlaceholderTxn::Merge(nsITransaction *aTransaction, PRBool *aDidMe } else { // merge typing or IME or deletion transactions if the selection matches - if (((mName.get() == nsHTMLEditor::gTypingTxnName) || - (mName.get() == nsHTMLEditor::gIMETxnName) || - (mName.get() == nsHTMLEditor::gDeleteTxnName)) + if (((mName.get() == nsEditor::gTypingTxnName) || + (mName.get() == nsEditor::gIMETxnName) || + (mName.get() == nsEditor::gDeleteTxnName)) && !mCommitted ) { // but only if this placeholder started with a collapsed selection diff --git a/mozilla/editor/base/SetDocTitleTxn.cpp b/mozilla/editor/base/SetDocTitleTxn.cpp index aa879c9651c..9d367d348a4 100644 --- a/mozilla/editor/base/SetDocTitleTxn.cpp +++ b/mozilla/editor/base/SetDocTitleTxn.cpp @@ -23,7 +23,6 @@ #include "SetDocTitleTxn.h" #include "nsEditor.h" -#include "nsHTMLEditor.h" #include "nsIDOMNode.h" #include "nsIDOMNodeList.h" #include "nsIDOMDocument.h" @@ -81,7 +80,8 @@ nsresult SetDocTitleTxn::SetDocTitle(nsString& aTitle) nsCOMPtr domDoc; nsCOMPtr editor = do_QueryInterface(mEditor); if (!editor) return NS_ERROR_FAILURE; - nsresult res = editor->GetDocument(getter_AddRefs(domDoc)); + nsresult rv = editor->GetDocument(getter_AddRefs(domDoc)); + if (NS_FAILED(rv)) return rv; if (!domDoc) return NS_ERROR_FAILURE; nsCOMPtr HTMLDoc = do_QueryInterface(domDoc); if (!HTMLDoc) return NS_ERROR_FAILURE; diff --git a/mozilla/editor/base/makefile.win b/mozilla/editor/base/makefile.win index 0133feb46c3..fe69d1b4d27 100644 --- a/mozilla/editor/base/makefile.win +++ b/mozilla/editor/base/makefile.win @@ -43,13 +43,15 @@ CPPSRCS = \ InsertElementTxn.cpp \ InsertTextTxn.cpp \ JoinElementTxn.cpp \ - nsComposerCommands.cpp \ nsEditorCommands.cpp \ + nsComposerCommands.cpp \ nsEditorController.cpp \ + nsComposerController.cpp \ nsEditor.cpp \ nsEditorEventListeners.cpp \ nsEditorUtils.cpp \ nsEditProperty.cpp \ + nsTextEditUtils.cpp \ nsHTMLEditUtils.cpp \ nsPlaintextDataTransfer.cpp \ nsPlaintextEditor.cpp \ diff --git a/mozilla/editor/base/nsEditor.cpp b/mozilla/editor/base/nsEditor.cpp index 51d6541f0a7..80020203c3f 100644 --- a/mozilla/editor/base/nsEditor.cpp +++ b/mozilla/editor/base/nsEditor.cpp @@ -28,7 +28,6 @@ #include "nsIDOMDocument.h" #include "nsIPref.h" #include "nsILocale.h" -#include "nsIEditProperty.h" // to be removed XXX #include "nsIDOMText.h" #include "nsIDOMElement.h" @@ -145,7 +144,6 @@ static const PRBool gNoisy = PR_FALSE; #endif -const PRUnichar nbsp = 160; PRInt32 nsEditor::gInstanceCount = 0; @@ -155,6 +153,9 @@ PRInt32 nsEditor::gInstanceCount = 0; // //--------------------------------------------------------------------------- +nsIAtom *nsEditor::gTypingTxnName; +nsIAtom *nsEditor::gIMETxnName; +nsIAtom *nsEditor::gDeleteTxnName; nsEditor::nsEditor() : mPresShellWeak(nsnull) @@ -184,10 +185,58 @@ nsEditor::nsEditor() NS_INIT_REFCNT(); PR_AtomicIncrement(&gInstanceCount); + + if (!gTypingTxnName) + gTypingTxnName = NS_NewAtom("Typing"); + else + NS_ADDREF(gTypingTxnName); + if (!gIMETxnName) + gIMETxnName = NS_NewAtom("IME"); + else + NS_ADDREF(gIMETxnName); + if (!gDeleteTxnName) + gDeleteTxnName = NS_NewAtom("Deleting"); + else + NS_ADDREF(gDeleteTxnName); } nsEditor::~nsEditor() { + /* first, delete the transaction manager if there is one. + this will release any remaining transactions. + this is important because transactions can hold onto the atoms (gTypingTxnName, ...) + and to make the optimization (holding refcounted statics) work correctly, + the editor instance needs to hold the last refcount. + If you get this wrong, expect to deref a garbage gTypingTxnName pointer if you bring up a second editor. + */ + if (mTxnMgr) { + mTxnMgr = 0; + } + nsrefcnt refCount=0; + if (gTypingTxnName) // we addref'd in the constructor + { // want to release it without nulling out the pointer. + refCount = gTypingTxnName->Release(); + if (0==refCount) { + gTypingTxnName = nsnull; + } + } + + if (gIMETxnName) // we addref'd in the constructor + { // want to release it without nulling out the pointer. + refCount = gIMETxnName->Release(); + if (0==refCount) { + gIMETxnName = nsnull; + } + } + + if (gDeleteTxnName) // we addref'd in the constructor + { // want to release it without nulling out the pointer. + refCount = gDeleteTxnName->Release(); + if (0==refCount) { + gDeleteTxnName = nsnull; + } + } + delete mEditorObservers; // no need to release observers; we didn't addref them mEditorObservers = 0; @@ -252,11 +301,6 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIPresShell* aPresShell, nsIContent *aRoot // is no way to do that right now. So we leave it null here and set // up a nav html dtd in nsHTMLEditor::Init - // Init mEditProperty - nsresult result = NS_NewEditProperty(getter_AddRefs(mEditProperty)); - if (NS_FAILED(result)) { return result; } - if (!mEditProperty) {return NS_ERROR_NULL_POINTER;} - ps->GetViewManager(&mViewManager); if (!mViewManager) {return NS_ERROR_NULL_POINTER;} mViewManager->Release(); //we want a weak link @@ -3033,102 +3077,6 @@ nsEditor::GetLengthOfDOMNode(nsIDOMNode *aNode, PRUint32 &aCount) return result; } -// Non-static version for the nsIEditor interface and JavaScript -NS_IMETHODIMP -nsEditor::NodeIsBlock(nsIDOMNode *aNode, PRBool &aIsBlock) -{ - if (!aNode) { return NS_ERROR_NULL_POINTER; } - return IsNodeBlock(aNode, aIsBlock); -} - -// The list of block nodes is shorter, so do the real work here... -nsresult -nsEditor::IsNodeBlock(nsIDOMNode *aNode, PRBool &aIsBlock) -{ - // this is a content-based implementation - if (!aNode) { return NS_ERROR_NULL_POINTER; } - - nsresult result = NS_ERROR_FAILURE; - aIsBlock = PR_FALSE; - nsCOMPtrelement; - element = do_QueryInterface(aNode); - if (element) - { - nsAutoString tagName; - result = element->GetTagName(tagName); - if (NS_SUCCEEDED(result)) - { - tagName.ToLowerCase(); - nsIAtom *tagAtom = NS_NewAtom(tagName); - if (!tagAtom) { return NS_ERROR_NULL_POINTER; } - - if (tagAtom==nsIEditProperty::p || - tagAtom==nsIEditProperty::div || - tagAtom==nsIEditProperty::blockquote || - tagAtom==nsIEditProperty::h1 || - tagAtom==nsIEditProperty::h2 || - tagAtom==nsIEditProperty::h3 || - tagAtom==nsIEditProperty::h4 || - tagAtom==nsIEditProperty::h5 || - tagAtom==nsIEditProperty::h6 || - tagAtom==nsIEditProperty::ul || - tagAtom==nsIEditProperty::ol || - tagAtom==nsIEditProperty::dl || - tagAtom==nsIEditProperty::pre || - tagAtom==nsIEditProperty::noscript || - tagAtom==nsIEditProperty::form || - tagAtom==nsIEditProperty::hr || - tagAtom==nsIEditProperty::table || - tagAtom==nsIEditProperty::fieldset || - tagAtom==nsIEditProperty::address || - tagAtom==nsIEditProperty::body || - tagAtom==nsIEditProperty::tr || - tagAtom==nsIEditProperty::td || - tagAtom==nsIEditProperty::th || - tagAtom==nsIEditProperty::caption || - tagAtom==nsIEditProperty::col || - tagAtom==nsIEditProperty::colgroup || - tagAtom==nsIEditProperty::tbody || - tagAtom==nsIEditProperty::thead || - tagAtom==nsIEditProperty::tfoot || - tagAtom==nsIEditProperty::li || - tagAtom==nsIEditProperty::dt || - tagAtom==nsIEditProperty::dd || - tagAtom==nsIEditProperty::legend ) - { - aIsBlock = PR_TRUE; - } - NS_RELEASE(tagAtom); - result = NS_OK; - } - } else { - // We don't have an element -- probably a text node - nsCOMPtrnodeAsText = do_QueryInterface(aNode); - if (nodeAsText) - { - aIsBlock = PR_FALSE; - result = NS_OK; - } - } - return result; -} - -// ...and simply assume non-block element is inline -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; - PRBool IsBlock = PR_FALSE; - result = IsNodeBlock(aNode, IsBlock); - aIsInline = !IsBlock; - return result; -} - - nsresult nsEditor::GetPriorNode(nsIDOMNode *aParentNode, PRInt32 aOffset, @@ -3892,238 +3840,6 @@ nsEditor::NodesSameType(nsIDOMNode *aNode1, nsIDOMNode *aNode2) } - -/////////////////////////////////////////////////////////////////////////// -// IsBlockNode: true if this node is an html block node -// -PRBool -nsEditor::IsBlockNode(nsIDOMNode *aNode) -{ - return !IsInlineNode(aNode); -} - - -/////////////////////////////////////////////////////////////////////////// -// IsInlineNode: true if this node is an html inline node -// -PRBool -nsEditor::IsInlineNode(nsIDOMNode *aNode) -{ - PRBool retVal = PR_FALSE; - IsNodeInline(aNode, retVal); - return retVal; -} - - -/////////////////////////////////////////////////////////////////////////// -// GetBlockNodeParent: returns enclosing block level ancestor, if any -// -nsCOMPtr -nsEditor::GetBlockNodeParent(nsIDOMNode *aNode) -{ - nsCOMPtr tmp; - nsCOMPtr p; - - if (!aNode) - { - NS_NOTREACHED("null node passed to GetBlockNodeParent()"); - return PR_FALSE; - } - - if (NS_FAILED(aNode->GetParentNode(getter_AddRefs(p)))) // no parent, ran off top of tree - return tmp; - - while (p && !IsBlockNode(p)) - { - if ( NS_FAILED(p->GetParentNode(getter_AddRefs(tmp))) || !tmp) // no parent, ran off top of tree - return p; - - p = tmp; - } - return p; -} - - -/////////////////////////////////////////////////////////////////////////// -// HasSameBlockNodeParent: true if nodes have same block level ancestor -// -PRBool -nsEditor::HasSameBlockNodeParent(nsIDOMNode *aNode1, nsIDOMNode *aNode2) -{ - if (!aNode1 || !aNode2) - { - NS_NOTREACHED("null node passed to HasSameBlockNodeParent()"); - return PR_FALSE; - } - - if (aNode1 == aNode2) - return PR_TRUE; - - nsCOMPtr p1 = GetBlockNodeParent(aNode1); - nsCOMPtr p2 = GetBlockNodeParent(aNode2); - - return (p1 == p2); -} - - -/////////////////////////////////////////////////////////////////////////// -// GetBlockSection: return leftmost/rightmost nodes in aChild's block -// -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", - (void*)(*aLeftNode), (void*)(*aRightNode)); } - - return result; -} - - -/////////////////////////////////////////////////////////////////////////// -// GetBlockSectionsForRange: return list of block sections that intersect -// this range -nsresult -nsEditor::GetBlockSectionsForRange(nsIDOMRange *aRange, nsISupportsArray *aSections) -{ - if (!aRange || !aSections) {return NS_ERROR_NULL_POINTER;} - - nsresult result; - nsCOMPtriter; - result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull, - NS_GET_IID(nsIContentIterator), getter_AddRefs(iter)); - if ((NS_SUCCEEDED(result)) && iter) - { - nsCOMPtr lastRange; - iter->Init(aRange); - nsCOMPtr currentContent; - iter->CurrentNode(getter_AddRefs(currentContent)); - while (NS_ENUMERATOR_FALSE == 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.get()) - { - 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", (void*)currentNode.get(), (void*)leftNode.get(), (void*)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->GetStartContainer(getter_AddRefs(lastStartNode)); - blockParentOfLastStartNode = do_QueryInterface(GetBlockNodeParent(lastStartNode)); - if (blockParentOfLastStartNode) - { - if (gNoisy) {printf("lastStartNode %p has block parent %p\n", (void*)lastStartNode.get(), (void*)blockParentOfLastStartNode.get());} - nsCOMPtr blockParentOfLeftNode; - blockParentOfLeftNode = do_QueryInterface(GetBlockNodeParent(leftNode)); - if (blockParentOfLeftNode) - { - if (gNoisy) {printf("leftNode %p has block parent %p\n", (void*)leftNode.get(), (void*)blockParentOfLeftNode.get());} - if (blockParentOfLastStartNode==blockParentOfLeftNode) { - addRange = PR_FALSE; - } - } - } - } - if (PR_TRUE==addRange) - { - if (gNoisy) {printf("adding range, setting lastRange with start node %p\n", (void*)leftNode.get());} - nsCOMPtr range; - result = nsComponentManager::CreateInstance(kCRangeCID, nsnull, - NS_GET_IID(nsIDOMRange), 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; -} - - /////////////////////////////////////////////////////////////////////////// // IsTextOrElementNode: true if node of dom type element or text // @@ -4215,61 +3931,6 @@ nsEditor::GetChildAt(nsIDOMNode *aParent, PRInt32 aOffset) -/////////////////////////////////////////////////////////////////////////// -// NextNodeInBlock: gets the next/prev node in the block, if any. Next node -// must be an element or text node, others are ignored -nsCOMPtr -nsEditor::NextNodeInBlock(nsIDOMNode *aNode, IterDirection aDir) -{ - nsCOMPtr nullNode; - nsCOMPtr content; - nsCOMPtr blockContent; - nsCOMPtr node; - nsCOMPtr blockParent; - - if (!aNode) return nullNode; - - nsCOMPtr iter; - if (NS_FAILED(nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull, - NS_GET_IID(nsIContentIterator), - getter_AddRefs(iter)))) - return nullNode; - - // much gnashing of teeth as we twit back and forth between content and domnode types - content = do_QueryInterface(aNode); - if (IsBlockNode(aNode)) - { - blockParent = do_QueryInterface(aNode); - } - else - { - blockParent = GetBlockNodeParent(aNode); - } - if (!blockParent) return nullNode; - blockContent = do_QueryInterface(blockParent); - if (!blockContent) return nullNode; - - if (NS_FAILED(iter->Init(blockContent))) return nullNode; - if (NS_FAILED(iter->PositionAt(content))) return nullNode; - - while (NS_ENUMERATOR_FALSE == iter->IsDone()) - { - if (NS_FAILED(iter->CurrentNode(getter_AddRefs(content)))) return nullNode; - // ignore nodes that aren't elements or text, or that are the block parent - node = do_QueryInterface(content); - if (node && IsTextOrElementNode(node) && (node != blockParent) && (node.get() != aNode)) - return node; - - if (aDir == kIterForward) - iter->Next(); - else - iter->Prev(); - } - - return nullNode; -} - - /////////////////////////////////////////////////////////////////////////// // GetStartNodeAndOffset: returns whatever the start parent & offset is of // the first range in the selection. @@ -4387,148 +4048,6 @@ nsEditor::IsPreformatted(nsIDOMNode *aNode, PRBool *aResult) } -/////////////////////////////////////////////////////////////////////////// -// IsNextCharWhitespace: checks the adjacent content in the same block -// to see if following selection is whitespace or nbsp -nsresult -nsEditor::IsNextCharWhitespace(nsIDOMNode *aParentNode, - PRInt32 aOffset, - PRBool *outIsSpace, - PRBool *outIsNBSP, - nsCOMPtr *outNode, - PRInt32 *outOffset) -{ - if (!outIsSpace || !outIsNBSP) return NS_ERROR_NULL_POINTER; - *outIsSpace = PR_FALSE; - *outIsNBSP = PR_FALSE; - if (outNode) *outNode = nsnull; - if (outOffset) *outOffset = -1; - - nsAutoString tempString; - PRUint32 strLength; - nsCOMPtr textNode = do_QueryInterface(aParentNode); - if (textNode) - { - textNode->GetLength(&strLength); - if ((PRUint32)aOffset < strLength) - { - // easy case: next char is in same node - textNode->SubstringData(aOffset,aOffset+1,tempString); - *outIsSpace = nsCRT::IsAsciiSpace(tempString.First()); - *outIsNBSP = (tempString.First() == nbsp); - if (outNode) *outNode = do_QueryInterface(aParentNode); - if (outOffset) *outOffset = aOffset+1; // yes, this is _past_ the character; - return NS_OK; - } - } - - // harder case: next char in next node. - nsCOMPtr node = NextNodeInBlock(aParentNode, kIterForward); - nsCOMPtr tmp; - while (node) - { - if (!IsInlineNode(node)) // skip over bold, italic, link, ect nodes - { - if (IsTextNode(node) && IsEditable(node)) - { - textNode = do_QueryInterface(node); - textNode->GetLength(&strLength); - if (strLength) - { - textNode->SubstringData(0,1,tempString); - *outIsSpace = nsCRT::IsAsciiSpace(tempString.First()); - *outIsNBSP = (tempString.First() == nbsp); - if (outNode) *outNode = do_QueryInterface(node); - if (outOffset) *outOffset = 1; // yes, this is _past_ the character; - return NS_OK; - } - // else it's an empty text node, or not editable; skip it. - } - else // node is an image or some other thingy that doesn't count as whitespace - { - break; - } - } - tmp = node; - node = NextNodeInBlock(tmp, kIterForward); - } - - return NS_OK; -} - - -/////////////////////////////////////////////////////////////////////////// -// IsPrevCharWhitespace: checks the adjacent content in the same block -// to see if following selection is whitespace -nsresult -nsEditor::IsPrevCharWhitespace(nsIDOMNode *aParentNode, - PRInt32 aOffset, - PRBool *outIsSpace, - PRBool *outIsNBSP, - nsCOMPtr *outNode, - PRInt32 *outOffset) -{ - if (!outIsSpace || !outIsNBSP) return NS_ERROR_NULL_POINTER; - *outIsSpace = PR_FALSE; - *outIsNBSP = PR_FALSE; - if (outNode) *outNode = nsnull; - if (outOffset) *outOffset = -1; - - nsAutoString tempString; - PRUint32 strLength; - nsCOMPtr textNode = do_QueryInterface(aParentNode); - if (textNode) - { - if (aOffset > 0) - { - // easy case: prev char is in same node - textNode->SubstringData(aOffset-1,aOffset,tempString); - *outIsSpace = nsCRT::IsAsciiSpace(tempString.First()); - *outIsNBSP = (tempString.First() == nbsp); - if (outNode) *outNode = do_QueryInterface(aParentNode); - if (outOffset) *outOffset = aOffset-1; - return NS_OK; - } - } - - // harder case: prev char in next node - nsCOMPtr node = NextNodeInBlock(aParentNode, kIterBackward); - nsCOMPtr tmp; - while (node) - { - if (!IsInlineNode(node)) // skip over bold, italic, link, ect nodes - { - if (IsTextNode(node) && IsEditable(node)) - { - textNode = do_QueryInterface(node); - textNode->GetLength(&strLength); - if (strLength) - { - // you could use nsITextContent::IsOnlyWhitespace here - textNode->SubstringData(strLength-1,strLength,tempString); - *outIsSpace = nsCRT::IsAsciiSpace(tempString.First()); - *outIsNBSP = (tempString.First() == nbsp); - if (outNode) *outNode = do_QueryInterface(aParentNode); - if (outOffset) *outOffset = strLength-1; - return NS_OK; - } - // else it's an empty text node, or not editable; skip it. - } - else // node is an image or some other thingy that doesn't count as whitespace - { - break; - } - } - // otherwise we found a node we want to skip, keep going - tmp = node; - node = NextNodeInBlock(tmp, kIterBackward); - } - - return NS_OK; - -} - - /////////////////////////////////////////////////////////////////////////// // SplitNodeDeep: this splits a node "deeply", splitting children as // appropriate. The place to split is represented by diff --git a/mozilla/editor/base/nsEditor.h b/mozilla/editor/base/nsEditor.h index 0d0510b8713..c63be7c628f 100644 --- a/mozilla/editor/base/nsEditor.h +++ b/mozilla/editor/base/nsEditor.h @@ -37,10 +37,8 @@ #include "nsIDOMRange.h" #include "nsIPrivateTextRange.h" #include "nsITransactionManager.h" -#include "TransactionFactory.h" #include "nsIComponentManager.h" #include "nsISupportsArray.h" -#include "nsIEditProperty.h" #include "nsIDOMCharacterData.h" #include "nsICSSStyleSheet.h" #include "nsIDTD.h" @@ -72,7 +70,6 @@ class RemoveStyleSheetTxn; class nsIFile; class nsISelectionController; - /** implementation of an editor object. it will be the controller/focal point * for the main editor services. i.e. the GUIManager, publishing, transaction * manager, event interfaces. the idea for the event interfaces is to have them @@ -483,15 +480,6 @@ public: nsCOMPtr *aParent, PRInt32 *aOffset); - /** set aIsInline to PR_TRUE if aNode is inline as defined by HTML DTD */ - static nsresult IsNodeInline(nsIDOMNode *aNode, PRBool &aIsInline); - - /** set aIsBlock to PR_TRUE if aNode is block as defined by HTML DTD */ - static nsresult IsNodeBlock(nsIDOMNode *aNode, PRBool &aIsBlock); - - /** This version is for exposure to JavaScript */ - NS_IMETHOD NodeIsBlock(nsIDOMNode *aNode, PRBool &aIsBlock); - /** 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. @@ -601,51 +589,12 @@ public: static nsresult GetTagString(nsIDOMNode *aNode, nsString& outString); static nsCOMPtr GetTag(nsIDOMNode *aNode); static PRBool NodesSameType(nsIDOMNode *aNode1, nsIDOMNode *aNode2); - static PRBool IsBlockNode(nsIDOMNode *aNode); - static PRBool IsInlineNode(nsIDOMNode *aNode); - static nsCOMPtr GetBlockNodeParent(nsIDOMNode *aNode); - static PRBool HasSameBlockNodeParent(nsIDOMNode *aNode1, nsIDOMNode *aNode2); - /** 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); - - static PRBool IsTextOrElementNode(nsIDOMNode *aNode); static PRBool IsTextNode(nsIDOMNode *aNode); static PRInt32 GetIndexOf(nsIDOMNode *aParent, nsIDOMNode *aChild); static nsCOMPtr GetChildAt(nsIDOMNode *aParent, PRInt32 aOffset); - static nsCOMPtr NextNodeInBlock(nsIDOMNode *aNode, IterDirection aDir); static nsresult GetStartNodeAndOffset(nsISelection *aSelection, nsCOMPtr *outStartNode, PRInt32 *outStartOffset); static nsresult GetEndNodeAndOffset(nsISelection *aSelection, nsCOMPtr *outEndNode, PRInt32 *outEndOffset); @@ -663,18 +612,6 @@ public: nsresult ClearSelection(); nsresult IsPreformatted(nsIDOMNode *aNode, PRBool *aResult); - nsresult IsNextCharWhitespace(nsIDOMNode *aParentNode, - PRInt32 aOffset, - PRBool *outIsSpace, - PRBool *outIsNBSP, - nsCOMPtr *outNode = 0, - PRInt32 *outOffset = 0); - nsresult IsPrevCharWhitespace(nsIDOMNode *aParentNode, - PRInt32 aOffset, - PRBool *outIsSpace, - PRBool *outIsNBSP, - nsCOMPtr *outNode = 0, - PRInt32 *outOffset = 0); nsresult SplitNodeDeep(nsIDOMNode *aNode, nsIDOMNode *aSplitPointParent, @@ -693,6 +630,13 @@ public: PRBool GetShouldTxnSetSelection(); void SetShouldTxnSetSelection(PRBool aShould); +public: + // Argh! These transaction names are used by PlaceholderTxn and + // nsPlaintextEditor. They should be localized to those classes. + static nsIAtom *gTypingTxnName; + static nsIAtom *gIMETxnName; + static nsIAtom *gDeleteTxnName; + protected: PRUint32 mFlags; // behavior flags. See nsPlaintextEditor.h for the flags we use. @@ -702,7 +646,6 @@ protected: nsIViewManager *mViewManager; PRInt32 mUpdateCount; nsCOMPtr mTxnMgr; - nsCOMPtr mEditProperty; nsCOMPtr mLastStyleSheet; // is owning this dangerous? nsWeakPtr mPlaceHolderTxn; // weak reference to placeholder for begin/end batch purposes nsIAtom *mPlaceHolderName; // name of placeholder transaction diff --git a/mozilla/editor/base/nsEditorController.cpp b/mozilla/editor/base/nsEditorController.cpp index 331850b8307..5d4c0c908ae 100644 --- a/mozilla/editor/base/nsEditorController.cpp +++ b/mozilla/editor/base/nsEditorController.cpp @@ -26,20 +26,8 @@ #include "nsIComponentManager.h" #include "nsEditorController.h" #include "nsIEditor.h" -#include "nsIEditorShell.h" -#include "nsIEditorMailSupport.h" -#include "nsIFormControlFrame.h" -#include "nsISelection.h" -#include "nsIHTMLEditor.h" -#include "nsISupportsPrimitives.h" -#include "nsXPIDLString.h" - -#include "nsISelectionController.h" -#include "nsIDocument.h" -#include "nsIPresShell.h" #include "nsEditorCommands.h" -#include "nsComposerCommands.h" NS_IMPL_ADDREF(nsEditorController) @@ -246,102 +234,3 @@ nsresult nsEditorController::GetEditorCommandManager(nsIControllerCommandManager return NS_OK; } - - -#ifdef XP_MAC -#pragma mark - -#endif - -nsComposerController::nsComposerController() -{ -} - -nsComposerController::~nsComposerController() -{ -} - -NS_IMETHODIMP nsComposerController::Init(nsISupports *aCommandRefCon) -{ - nsresult rv; - - rv = nsEditorController::Init(aCommandRefCon); - if (NS_FAILED(rv)) return rv; - - mCommandManager = do_CreateInstance("@mozilla.org/content/controller-command-manager;1", &rv); - if (NS_FAILED(rv)) return rv; - - // register the commands. - rv = nsComposerController::RegisterComposerCommands(mCommandManager); - if (NS_FAILED(rv)) return rv; - - return NS_OK; -} - -#define NS_REGISTER_STYLE_COMMAND(_cmdClass, _cmdName, _styleTag) \ - { \ - _cmdClass* theCmd = new _cmdClass(_styleTag); \ - if (!theCmd) return NS_ERROR_OUT_OF_MEMORY; \ - rv = inCommandManager->RegisterCommand(NS_LITERAL_STRING(_cmdName), \ - NS_STATIC_CAST(nsIControllerCommand *, theCmd)); \ - } - - -// static -nsresult nsComposerController::RegisterComposerCommands(nsIControllerCommandManager *inCommandManager) -{ - nsresult rv; - - // File menu - NS_REGISTER_FIRST_COMMAND(nsPrintingCommands, "cmd_print"); - NS_REGISTER_NEXT_COMMAND(nsPrintingCommands, "cmd_printSetup"); - NS_REGISTER_NEXT_COMMAND(nsPrintingCommands,"cmd_print_button"); - NS_REGISTER_LAST_COMMAND(nsPrintingCommands, "cmd_printPreview"); - - // Edit menu - NS_REGISTER_ONE_COMMAND(nsPasteQuotationCommand, "cmd_pasteQuote"); - - // indent/outdent - NS_REGISTER_ONE_COMMAND(nsIndentCommand, "cmd_indent"); - NS_REGISTER_ONE_COMMAND(nsOutdentCommand, "cmd_outdent"); - - // Styles - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_bold", "b"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_italic", "i"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_underline", "u"); - - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_strikethrough", "strike"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_superscript", "sup"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_subscript", "sub"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_nobreak", "nobr"); - - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_em", "em"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_strong", "strong"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_cite", "cite"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_abbr", "abbr"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_acronym", "acronym"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_code", "code"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_samp", "samp"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_var", "var"); - - // lists - NS_REGISTER_STYLE_COMMAND(nsListCommand, "cmd_ol", "ol"); - NS_REGISTER_STYLE_COMMAND(nsListCommand, "cmd_ul", "ul"); - NS_REGISTER_STYLE_COMMAND(nsListItemCommand, "cmd_dt", "dt"); - NS_REGISTER_STYLE_COMMAND(nsListItemCommand, "cmd_dd", "dd"); - NS_REGISTER_ONE_COMMAND(nsRemoveListCommand, "cmd_removeList"); - - // format stuff - NS_REGISTER_ONE_COMMAND(nsParagraphStateCommand, "cmd_paragraphState"); - NS_REGISTER_ONE_COMMAND(nsFontFaceStateCommand, "cmd_fontFace"); - NS_REGISTER_ONE_COMMAND(nsFontColorStateCommand, "cmd_fontColor"); - NS_REGISTER_ONE_COMMAND(nsBackgroundColorStateCommand, "cmd_backgroundColor"); - - NS_REGISTER_ONE_COMMAND(nsAlignCommand, "cmd_align"); - NS_REGISTER_ONE_COMMAND(nsRemoveStylesCommand, "cmd_removeStyles"); - - NS_REGISTER_ONE_COMMAND(nsIncreaseFontSizeCommand, "cmd_increaseFont"); - NS_REGISTER_ONE_COMMAND(nsDecreaseFontSizeCommand, "cmd_decreaseFont"); - - return NS_OK; -} - diff --git a/mozilla/editor/base/nsEditorController.h b/mozilla/editor/base/nsEditorController.h index 5546bb702eb..dbf3f9e3982 100644 --- a/mozilla/editor/base/nsEditorController.h +++ b/mozilla/editor/base/nsEditorController.h @@ -20,12 +20,12 @@ * Contributor(s): */ +#ifndef nsEditorController_h__ +#define nsEditorController_h__ + #define NS_EDITORCONTROLLER_CID \ { 0x26fb965c, 0x9de6, 0x11d3, { 0xbc, 0xcc, 0x0, 0x60, 0xb0, 0xfc, 0x76, 0xbd } } -#define NS_COMPOSERCONTROLLER_CID \ -{ 0x50e95301, 0x17a8, 0x11d4, { 0x9f, 0x7e, 0xdd, 0x53, 0x0d, 0x5f, 0x05, 0x7c } } - #include "nsIController.h" #include "nsIEditorController.h" @@ -37,7 +37,6 @@ #include "nsWeakPtr.h" class nsIEditor; -class nsIEditorShell; // the editor controller is used for both text widgets, and basic text editing @@ -91,23 +90,5 @@ private: }; +#endif /* nsEditorController_h__ */ - -// the editor controller is used for composer only (and other HTML compose -// areas). The refCon that gets passed to its commands is an nsIEditorShell. - -class nsComposerController : public nsEditorController -{ -public: - - nsComposerController(); - virtual ~nsComposerController(); - - /** init the controller */ - NS_IMETHOD Init(nsISupports *aCommandRefCon); - -private: - - static nsresult RegisterComposerCommands(nsIControllerCommandManager* inCommandManager); - -}; diff --git a/mozilla/editor/base/nsEditorEventListeners.cpp b/mozilla/editor/base/nsEditorEventListeners.cpp index a318564349f..bc6450b5ac2 100644 --- a/mozilla/editor/base/nsEditorEventListeners.cpp +++ b/mozilla/editor/base/nsEditorEventListeners.cpp @@ -32,7 +32,6 @@ #include "nsIDOMElement.h" #include "nsISelection.h" #include "nsIDOMCharacterData.h" -#include "nsIEditProperty.h" #include "nsISupportsArray.h" #include "nsIStringStream.h" #include "nsIDOMKeyEvent.h" diff --git a/mozilla/editor/base/nsEditorRegistration.cpp b/mozilla/editor/base/nsEditorRegistration.cpp index f262c18cdd5..df7e4b59ee5 100644 --- a/mozilla/editor/base/nsEditorRegistration.cpp +++ b/mozilla/editor/base/nsEditorRegistration.cpp @@ -23,23 +23,33 @@ #include "nsIGenericFactory.h" #include "nsEditorCID.h" -#include "nsEditorShell.h" // for the CID #include "nsEditor.h" // for gInstanceCount -#include "nsEditorController.h" //CID #include "nsEditorService.h" +#include "nsHTMLEditor.h" #include "nsPlaintextEditor.h" +#include "nsEditorController.h" //CID + +#define DO_COMPOSER_TOO 1 +#ifdef DO_COMPOSER_TOO +#include "nsComposerController.h" //CID +#include "nsEditorShell.h" // for the CID +#endif /* DO_COMPOSER_TOO */ + + //////////////////////////////////////////////////////////////////////// // Define the contructor function for the objects // // NOTE: This creates an instance of objects by using the default constructor // -NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorShell) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorController) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsComposerController) NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorService) NS_GENERIC_FACTORY_CONSTRUCTOR(nsPlaintextEditor) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorController) +#ifdef DO_COMPOSER_TOO +NS_GENERIC_FACTORY_CONSTRUCTOR(nsComposerController) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorShell) +#endif /* DO_COMPOSER_TOO */ #ifdef ENABLE_EDITOR_API_LOG #include "nsHTMLEditorLog.h" @@ -63,14 +73,6 @@ static nsModuleComponentInfo components[] = { { "HTML Editor", NS_HTMLEDITOR_CID, "@mozilla.org/editor/htmleditor;1", nsHTMLEditorConstructor, }, #endif - { "Editor Controller", NS_EDITORCONTROLLER_CID, - "@mozilla.org/editor/editorcontroller;1", nsEditorControllerConstructor, }, - { "Composer Controller", NS_COMPOSERCONTROLLER_CID, - "@mozilla.org/editor/composercontroller;1", nsComposerControllerConstructor, }, - { "Editor Shell Component", NS_EDITORSHELL_CID, - "@mozilla.org/editor/editorshell;1", nsEditorShellConstructor, }, - { "Editor Shell Spell Checker", NS_EDITORSHELL_CID, - "@mozilla.org/editor/editorspellcheck;1", nsEditorShellConstructor, }, { "Editor Service", NS_EDITORSERVICE_CID, "@mozilla.org/editor/editorservice;1", nsEditorServiceConstructor,}, { "Editor Startup Handler", NS_EDITORSERVICE_CID, @@ -81,6 +83,18 @@ static nsModuleComponentInfo components[] = { { "Edit Startup Handler", NS_EDITORSERVICE_CID, "@mozilla.org/commandlinehandler/general-startup;1?type=edit", nsEditorServiceConstructor, }, + { "Editor Controller", NS_EDITORCONTROLLER_CID, + "@mozilla.org/editor/editorcontroller;1", + nsEditorControllerConstructor, }, +#ifdef DO_COMPOSER_TOO + { "Composer Controller", NS_COMPOSERCONTROLLER_CID, + "@mozilla.org/editor/composercontroller;1", + nsComposerControllerConstructor, }, + { "Editor Shell Component", NS_EDITORSHELL_CID, + "@mozilla.org/editor/editorshell;1", nsEditorShellConstructor, }, + { "Editor Shell Spell Checker", NS_EDITORSHELL_CID, + "@mozilla.org/editor/editorspellcheck;1", nsEditorShellConstructor, }, +#endif /* DO_COMPOSER_TOO */ }; //////////////////////////////////////////////////////////////////////// diff --git a/mozilla/editor/base/nsEditorShell.cpp b/mozilla/editor/base/nsEditorShell.cpp index b1b21fa5d95..11e29960ef6 100644 --- a/mozilla/editor/base/nsEditorShell.cpp +++ b/mozilla/editor/base/nsEditorShell.cpp @@ -83,7 +83,7 @@ #include "nsICommonDialogs.h" #include "nsIEditorController.h" -#include "nsEditorController.h" +//#include "nsEditorController.h" #include "nsIControllers.h" #include "nsIDocShell.h" #include "nsIDocShellTreeItem.h" @@ -124,8 +124,6 @@ #include "nsISpellChecker.h" #include "nsInterfaceState.h" -#include "nsAOLCiter.h" -#include "nsInternetCiter.h" #include "nsEditorShellMouseListener.h" /////////////////////////////////////// @@ -2285,9 +2283,7 @@ nsEditorShell::NodeIsBlock(nsIDOMNode *node, PRBool *_retval) case ePlainTextEditorType: case eHTMLTextEditorType: { - nsCOMPtr editor = do_QueryInterface(mEditor); - if (editor) - rv = editor->NodeIsBlock(node, *_retval); + rv = mEditor->NodeIsBlock(node, *_retval); } break; @@ -2534,174 +2530,22 @@ nsEditorShell::InsertAsCitedQuotation(const PRUnichar *quotedText, return err; } -// Utility routine to make a new citer. This addrefs, of course. -static nsICiter* MakeACiter() -{ - // Make a citer of an appropriate type - nsICiter* citer = 0; - nsresult rv; - NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &rv); - if (NS_FAILED(rv)) return 0; - - char *citationType = 0; - rv = prefs->CopyCharPref("mail.compose.citationType", &citationType); - - if (NS_SUCCEEDED(rv) && citationType[0]) - { - if (!strncmp(citationType, "aol", 3)) - citer = new nsAOLCiter; - else - citer = new nsInternetCiter; - PL_strfree(citationType); - } - else - citer = new nsInternetCiter; - - if (citer) - NS_ADDREF(citer); - return citer; -} - NS_IMETHODIMP nsEditorShell::Rewrap(PRBool aRespectNewlines) { - PRInt32 wrapCol; - nsresult rv = GetWrapColumn(&wrapCol); - if (NS_FAILED(rv)) - return NS_OK; -#ifdef DEBUG_akkana - printf("nsEditorShell::Rewrap to %ld columns\n", (long)wrapCol); -#endif - - nsCOMPtr selection; - rv = GetEditorSelection(getter_AddRefs(selection)); - if (NS_FAILED(rv)) return rv; - - if (!selection) - return NS_ERROR_NOT_INITIALIZED; - PRBool isCollapsed; - rv = selection->GetIsCollapsed(&isCollapsed); - if (NS_FAILED(rv)) return rv; - - // Variables we'll need either way - nsAutoString format; format.AssignWithConversion("text/plain"); - nsAutoString current; - nsString wrapped; - nsCOMPtr nsied (do_QueryInterface(mEditor)); - if (!nsied) - return NS_ERROR_UNEXPECTED; - - if (isCollapsed) // rewrap the whole document - { - rv = nsied->OutputToString(current, format, - nsIDocumentEncoder::OutputFormatted); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr citer = dont_AddRef(MakeACiter()); - if (NS_FAILED(rv)) return rv; - if (!citer) return NS_ERROR_UNEXPECTED; - - rv = citer->Rewrap(current, wrapCol, 0, aRespectNewlines, wrapped); - if (NS_FAILED(rv)) return rv; - - rv = SelectAll(); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr textEditor (do_QueryInterface(mEditor)); - if (!textEditor) - return NS_NOINTERFACE; - return textEditor->InsertText(wrapped.GetUnicode()); - } - else // rewrap only the selection - { - rv = nsied->OutputToString(current, format, - nsIDocumentEncoder::OutputFormatted - | nsIDocumentEncoder::OutputSelectionOnly); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr citer = dont_AddRef(MakeACiter()); - if (NS_FAILED(rv)) return rv; - if (!citer) return NS_ERROR_UNEXPECTED; - - PRUint32 firstLineOffset = 0; // XXX need to get this - rv = citer->Rewrap(current, wrapCol, firstLineOffset, aRespectNewlines, - wrapped); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr textEditor (do_QueryInterface(mEditor)); - if (!textEditor) - return NS_NOINTERFACE; - return textEditor->InsertText(wrapped.GetUnicode()); - } - return NS_OK; + nsCOMPtr mailEditor = do_QueryInterface(mEditor); + if (!mailEditor) + return NS_NOINTERFACE; + return mailEditor->Rewrap(aRespectNewlines); } NS_IMETHODIMP nsEditorShell::StripCites() { -#ifdef DEBUG_akkana - printf("nsEditorShell::StripCites()\n"); -#endif - - nsCOMPtr selection; - nsresult rv = GetEditorSelection(getter_AddRefs(selection)); - if (NS_FAILED(rv)) return rv; - - if (!selection) - return NS_ERROR_NOT_INITIALIZED; - PRBool isCollapsed; - rv = selection->GetIsCollapsed(&isCollapsed); - if (NS_FAILED(rv)) return rv; - - // Variables we'll need either way - nsAutoString format; format.AssignWithConversion("text/plain"); - nsAutoString current; - nsString stripped; - nsCOMPtr nsied (do_QueryInterface(mEditor)); - if (!nsied) - return NS_ERROR_UNEXPECTED; - - if (isCollapsed) // rewrap the whole document - { - rv = nsied->OutputToString(current, format, - nsIDocumentEncoder::OutputFormatted); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr citer = dont_AddRef(MakeACiter()); - if (NS_FAILED(rv)) return rv; - if (!citer) return NS_ERROR_UNEXPECTED; - - rv = citer->StripCites(current, stripped); - if (NS_FAILED(rv)) return rv; - - rv = SelectAll(); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr textEditor (do_QueryInterface(mEditor)); - if (!textEditor) - return NS_NOINTERFACE; - return textEditor->InsertText(stripped.GetUnicode()); - } - else // rewrap only the selection - { - rv = nsied->OutputToString(current, format, - nsIDocumentEncoder::OutputFormatted - | nsIDocumentEncoder::OutputSelectionOnly); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr citer = dont_AddRef(MakeACiter()); - if (NS_FAILED(rv)) return rv; - if (!citer) return NS_ERROR_UNEXPECTED; - - rv = citer->StripCites(current, stripped); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr textEditor (do_QueryInterface(mEditor)); - if (!textEditor) - return NS_NOINTERFACE; - return textEditor->InsertText(stripped.GetUnicode()); - } - return NS_OK; + nsCOMPtr mailEditor = do_QueryInterface(mEditor); + if (!mailEditor) + return NS_NOINTERFACE; + return mailEditor->StripCites(); } NS_IMETHODIMP diff --git a/mozilla/editor/base/nsEditorShellMouseListener.cpp b/mozilla/editor/base/nsEditorShellMouseListener.cpp index ae4a9066bb5..ea5b2c528a7 100644 --- a/mozilla/editor/base/nsEditorShellMouseListener.cpp +++ b/mozilla/editor/base/nsEditorShellMouseListener.cpp @@ -40,7 +40,6 @@ #include "nsIEditor.h" #include "nsIHTMLEditor.h" -#include "nsHTMLEditUtils.h" /* * nsEditorShellMouseListener implementation @@ -270,17 +269,19 @@ nsEditorShellMouseListener::MouseDown(nsIDOMEvent* aMouseEvent) } } +#ifdef CMANSKE_PLEASE_FIX_THIS if (isContextClick) { // Set selection to node clicked on if NOT within an existing selection // and not the entire body or table element if (element && !NodeIsInSelection && - !nsHTMLEditUtils::IsBody(element) && + !nsTextEditUtils::IsBody(element) && !nsHTMLEditUtils::IsTableElement(element)) { mEditorShell->SelectElement(element); } } +#endif /* CMANSKE_PLEASE_FIX_THIS */ else if (buttonNumber == 0) { if (tableMode && clickCount == 2) diff --git a/mozilla/editor/base/nsEditorUtils.h b/mozilla/editor/base/nsEditorUtils.h index 4827800df70..8fb8407a443 100644 --- a/mozilla/editor/base/nsEditorUtils.h +++ b/mozilla/editor/base/nsEditorUtils.h @@ -32,9 +32,10 @@ #include "nsIAtom.h" #include "nsVoidArray.h" #include "nsEditor.h" -#include "nsPlaintextEditor.h" #include "nsIContentIterator.h" +class nsPlaintextEditor; + /*************************************************************************** * stack based helper class for batching a collection of txns inside a * placeholder txn. @@ -49,23 +50,6 @@ class nsAutoPlaceHolderBatch ~nsAutoPlaceHolderBatch() { if (mEd) mEd->EndPlaceHolderTransaction(); } }; -/*************************************************************************** - * stack based helper class for detecting end of editor initialization, in - * order to triger "end of init" initialization of the edit rules. - */ -class nsAutoEditInitRulesTrigger -{ - private: - nsPlaintextEditor *mEd; - nsresult &mRes; - public: - nsAutoEditInitRulesTrigger( nsPlaintextEditor *aEd, nsresult &aRes) : mEd(aEd), mRes(aRes) - { if (mEd) mEd->BeginEditorInit(); } - ~nsAutoEditInitRulesTrigger() { if (mEd) mRes = mEd->EndEditorInit(); } -}; - - - /*************************************************************************** * stack based helper class for batching a collection of txns. * Note: I changed this to use placeholder batching so that we get diff --git a/mozilla/editor/base/nsHTMLDataTransfer.cpp b/mozilla/editor/base/nsHTMLDataTransfer.cpp index d6894dc2b59..217207bd770 100644 --- a/mozilla/editor/base/nsHTMLDataTransfer.cpp +++ b/mozilla/editor/base/nsHTMLDataTransfer.cpp @@ -23,6 +23,7 @@ #include "nsHTMLEditor.h" #include "nsHTMLEditRules.h" +#include "nsTextEditUtils.h" #include "nsHTMLEditUtils.h" #include "nsEditorEventListeners.h" @@ -81,7 +82,6 @@ #include "nsAOLCiter.h" #include "nsInternetCiter.h" #include "nsISupportsPrimitives.h" -#include "InsertTextTxn.h" // netwerk #include "nsIURI.h" @@ -94,10 +94,6 @@ #include "nsIDragService.h" #include "nsIDOMNSUIEvent.h" -// Transactionas -#include "PlaceholderTxn.h" -#include "nsStyleSheetTxns.h" - // Misc #include "TextEditorTest.h" #include "nsEditorUtils.h" @@ -466,7 +462,7 @@ nsresult nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsString& aInputStr NS_ENSURE_TRUE(curNode, NS_ERROR_FAILURE); NS_ENSURE_TRUE(curNode != fragmentAsNode, NS_ERROR_FAILURE); - NS_ENSURE_TRUE(!nsHTMLEditUtils::IsBody(curNode), NS_ERROR_FAILURE); + NS_ENSURE_TRUE(!nsTextEditUtils::IsBody(curNode), NS_ERROR_FAILURE); if (insertedContextParent) { @@ -512,7 +508,7 @@ nsresult nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsString& aInputStr while (NS_FAILED(res) && curNode) { curNode->GetParentNode(getter_AddRefs(parent)); - if (parent && !nsHTMLEditUtils::IsBody(parent)) + if (parent && !nsTextEditUtils::IsBody(parent)) { res = InsertNodeAtPoint(parent, parentNode, offsetOfNewNode, PR_TRUE); if (NS_SUCCEEDED(res)) @@ -1326,41 +1322,15 @@ NS_IMETHODIMP nsHTMLEditor::InsertAsQuotation(const nsString& aQuotedText, charset, aNodeInserted); } -// text insert. +// Insert plaintext as a quotation, with cite marks (e.g. "> "). +// This differs from its corresponding method in nsPlaintextEditor +// in that here, quoted material is enclosed in a
 tag
+// in order to preserve the original line wrapping.
 NS_IMETHODIMP
 nsHTMLEditor::InsertAsPlaintextQuotation(const nsString& aQuotedText,
                                          nsIDOMNode **aNodeInserted)
 {
-  // We have the text.  Cite it appropriately:
-  nsCOMPtr citer;
   nsresult rv;
-  NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &rv);
-  if (NS_FAILED(rv)) return rv;
-
-  char *citationType = 0;
-  rv = prefs->CopyCharPref("mail.compose.citationType", &citationType);
-                          
-  if (NS_SUCCEEDED(rv) && citationType[0])
-  {
-    if (!strncmp(citationType, "aol", 3))
-      citer = new nsAOLCiter;
-    else
-      citer = new nsInternetCiter;
-    PL_strfree(citationType);
-  }
-  else
-    citer = new nsInternetCiter;
-  
-  // Let the citer quote it for us:
-  nsString quotedStuff;
-  rv = citer->GetCiteString(aQuotedText, quotedStuff);
-  if (!NS_SUCCEEDED(rv))
-    return rv;
-
-  // It's best to put a blank line after the quoted text so that mails
-  // written without thinking won't be so ugly.
-  quotedStuff.Append(PRUnichar('\n'));
-
   nsCOMPtr preNode;
   // get selection
   nsCOMPtr selection;
@@ -1406,7 +1376,8 @@ nsHTMLEditor::InsertAsPlaintextQuotation(const nsString& aQuotedText,
         selection->Collapse(preNode, 0);
       }
 
-      rv = InsertText(quotedStuff.GetUnicode());
+      //rv = InsertText(quotedStuff.GetUnicode());
+      rv = nsPlaintextEditor::InsertAsQuotation(aQuotedText, aNodeInserted);
 
       if (aNodeInserted && NS_SUCCEEDED(rv))
       {
@@ -1570,7 +1541,7 @@ nsresult nsHTMLEditor::CreateDOMFragmentFromPaste(nsIDOMNSRange *aNSRange,
     PRInt32 err, sep;
     sep = aInfoStr.FindChar((PRUnichar)',');
     aInfoStr.Left(numstr1, sep);
-    aInfoStr.Mid(numstr2, sep+1, -1);
+    aInfoStr.Right(numstr2, sep+1);
     *outRangeStartHint = numstr1.ToInteger(&err) + contextDepth;
     *outRangeEndHint   = numstr2.ToInteger(&err) + contextDepth;
   }
diff --git a/mozilla/editor/base/nsHTMLEditRules.cpp b/mozilla/editor/base/nsHTMLEditRules.cpp
index 7d6a6d0902f..1d066339fd5 100644
--- a/mozilla/editor/base/nsHTMLEditRules.cpp
+++ b/mozilla/editor/base/nsHTMLEditRules.cpp
@@ -29,8 +29,10 @@
 #include "nsHTMLEditRules.h"
 
 #include "nsEditor.h"
+#include "nsTextEditUtils.h"
 #include "nsHTMLEditUtils.h"
 #include "nsHTMLEditor.h"
+#include "TypeInState.h"
 
 #include "nsIContent.h"
 #include "nsIContentIterator.h"
@@ -77,7 +79,18 @@ enum
 /********************************************************
  *  first some helpful funcotrs we will use
  ********************************************************/
- 
+
+static PRBool IsBlockNode(nsIDOMNode* node)
+{
+  PRBool isBlock (PR_FALSE);
+  nsHTMLEditor::NodeIsBlockStatic(node, isBlock);
+  return isBlock;
+}
+
+static PRBool IsInlineNode(nsIDOMNode* node)
+{
+  return !IsBlockNode(node);
+}
  
 class nsTableCellAndListItemFunctor : public nsBoolDomIterFunctor
 {
@@ -95,7 +108,7 @@ class nsBRNodeFunctor : public nsBoolDomIterFunctor
   public:
     virtual PRBool operator()(nsIDOMNode* aNode)  // used to build list of all td's & th's iterator covers
     {
-      if (nsHTMLEditUtils::IsBreak(aNode)) return PR_TRUE;
+      if (nsTextEditUtils::IsBreak(aNode)) return PR_TRUE;
       return PR_FALSE;
     }
 };
@@ -759,7 +772,7 @@ nsHTMLEditRules::GetParagraphState(PRBool &aMixed, nsString &outFormat)
     nsAutoString format;
     nsCOMPtr atom = mHTMLEditor->GetTag(curNode);
     
-    if (mHTMLEditor->IsInlineNode(curNode))
+    if (IsInlineNode(curNode))
     {
       nsCOMPtr block = mHTMLEditor->GetBlockNodeParent(curNode);
       if (block)
@@ -851,10 +864,10 @@ nsHTMLEditRules::WillInsert(nsISelection *aSelection, PRBool *aCancel)
   // get prior node
   res = mHTMLEditor->GetPriorHTMLNode(selNode, selOffset,
                                       address_of(priorNode));
-  if (NS_SUCCEEDED(res) && priorNode && nsHTMLEditUtils::IsMozBR(priorNode))
+  if (NS_SUCCEEDED(res) && priorNode && nsTextEditUtils::IsMozBR(priorNode))
   {
     nsCOMPtr block1, block2;
-    if (mHTMLEditor->IsBlockNode(selNode)) block1 = selNode;
+    if (IsBlockNode(selNode)) block1 = selNode;
     else block1 = mHTMLEditor->GetBlockNodeParent(selNode);
     block2 = mHTMLEditor->GetBlockNodeParent(priorNode);
   
@@ -1153,7 +1166,7 @@ nsHTMLEditRules::WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBo
   // identify the block
   nsCOMPtr blockParent;
   
-  if (nsEditor::IsBlockNode(node)) 
+  if (IsBlockNode(node)) 
     blockParent = node;
   else 
     blockParent = mHTMLEditor->GetBlockNodeParent(node);
@@ -1199,7 +1212,7 @@ nsHTMLEditRules::WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBo
     // Then we stick to the left to aviod an uber caret.
     nsCOMPtr siblingNode;
     brNode->GetNextSibling(getter_AddRefs(siblingNode));
-    if (siblingNode && mHTMLEditor->IsBlockNode(siblingNode))
+    if (siblingNode && IsBlockNode(siblingNode))
       selPriv->SetInterlinePosition(PR_FALSE);
     else 
       selPriv->SetInterlinePosition(PR_TRUE);
@@ -1408,7 +1421,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
             }
             return res;
           }
-          else if ( mHTMLEditor->IsInlineNode(priorNode) )
+          else if ( IsInlineNode(priorNode) )
           {
             // remember where we are
             PRInt32 offset;
@@ -1471,7 +1484,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
         if (NS_FAILED(res)) return res;
          
         // if there is no next node, or it's not in the body, then cancel the deletion
-        if (!nextNode || !nsHTMLEditUtils::InBody(nextNode, mHTMLEditor))
+        if (!nextNode || !nsTextEditUtils::InBody(nextNode, mHTMLEditor))
         {
           *aCancel = PR_TRUE;
           return res;
@@ -1519,7 +1532,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
             }
             return res;
           }
-          else if ( mHTMLEditor->IsInlineNode(nextNode) )
+          else if ( IsInlineNode(nextNode) )
           {
             PRInt32 offset;
             nsCOMPtr node;
@@ -1615,7 +1628,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
         }
         
         if (maybeBreak && maybeBlock &&
-            nsHTMLEditUtils::IsBreak(maybeBreak) && nsEditor::IsBlockNode(maybeBlock))
+            nsTextEditUtils::IsBreak(maybeBreak) && IsBlockNode(maybeBlock))
           nodeToDelete = maybeBreak;
         else if (aAction == nsIEditor::ePrevious)
           res = mHTMLEditor->GetPriorHTMLNode(startNode, startOffset, address_of(nodeToDelete));
@@ -1656,11 +1669,11 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
         // there is a br in front of it. If so, we must delete both.
         // else you get this: deletion code deletes mozBR, then selection
         // adjusting code puts it back in.  doh
-        if (nsHTMLEditUtils::IsMozBR(nodeToDelete))
+        if (nsTextEditUtils::IsMozBR(nodeToDelete))
         {
           nsCOMPtr brNode;
           res = mHTMLEditor->GetPriorHTMLNode(nodeToDelete, address_of(brNode));
-          if (nsHTMLEditUtils::IsBreak(brNode))
+          if (nsTextEditUtils::IsBreak(brNode))
           {
             // is brNode also a descendant of same block?
             nsCOMPtr block, brBlock;
@@ -1717,12 +1730,12 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
     //
     //      Should we be calling IsBlockNode() instead of IsBody() here?
 
-    if (nsHTMLEditUtils::IsBody(startNode))
+    if (nsTextEditUtils::IsBody(startNode))
       leftParent = startNode;
     else
       leftParent = mHTMLEditor->GetBlockNodeParent(startNode);
 
-    if (nsHTMLEditUtils::IsBody(endNode))
+    if (nsTextEditUtils::IsBody(endNode))
       rightParent = endNode;
     else
       rightParent = mHTMLEditor->GetBlockNodeParent(endNode);
@@ -1936,7 +1949,7 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection,
     nsCOMPtr isupports = dont_AddRef(arrayOfNodes->ElementAt(j));
     nsCOMPtr curNode( do_QueryInterface(isupports ) );
     // if curNode is not a Break, we're done
-    if (!nsHTMLEditUtils::IsBreak(curNode)) 
+    if (!nsTextEditUtils::IsBreak(curNode)) 
     {
       bOnlyBreaks = PR_FALSE;
       break;
@@ -2043,7 +2056,7 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection,
     if (NS_FAILED(res)) return res;
   
     // if curNode is a Break, delete it, and quit remembering prev list item
-    if (nsHTMLEditUtils::IsBreak(curNode)) 
+    if (nsTextEditUtils::IsBreak(curNode)) 
     {
       res = mHTMLEditor->DeleteNode(curNode);
       if (NS_FAILED(res)) return res;
@@ -2051,7 +2064,7 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection,
       continue;
     }
     // if curNode is an empty inline container, delete it
-    else if (mHTMLEditor->IsInlineNode(curNode) && mHTMLEditor->IsContainer(curNode)) 
+    else if (IsInlineNode(curNode) && mHTMLEditor->IsContainer(curNode)) 
     {
       PRBool bEmpty;
       res = mHTMLEditor->IsEmptyNode(curNode, &bEmpty);
@@ -2165,7 +2178,7 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection,
     nsCOMPtr listItem;
     if (!nsHTMLEditUtils::IsListItem(curNode))
     {
-      if (nsEditor::IsInlineNode(curNode) && prevListItem)
+      if (IsInlineNode(curNode) && prevListItem)
       {
         // this is a continuation of some inline nodes that belong together in
         // the same list item.  use prevListItem
@@ -2187,7 +2200,7 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection,
           res = mHTMLEditor->InsertContainerAbove(curNode, address_of(listItem), itemType);
         }
         if (NS_FAILED(res)) return res;
-        if (nsEditor::IsInlineNode(curNode)) 
+        if (IsInlineNode(curNode)) 
           prevListItem = listItem;
       }
     }
@@ -2625,7 +2638,7 @@ nsHTMLEditRules::WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool *
       // this is a hack until i think about outdent for real.
       nsCOMPtr n = curNode;
       nsCOMPtr tmp;
-      while (!nsHTMLEditUtils::IsBody(n))
+      while (!nsTextEditUtils::IsBody(n))
       {
         if (nsHTMLEditUtils::IsBlockquote(n))
         {
@@ -2726,7 +2739,7 @@ nsHTMLEditRules::CreateStyleForInsertText(nsISelection *aSelection, nsIDOMDocume
       if (NS_FAILED(res)) return res;
       // don't try to split br's...
       // note: probably should only split containers, but being more conservative in changes for now.
-      if (nsHTMLEditUtils::IsBreak(secondSplitParent))
+      if (nsTextEditUtils::IsBreak(secondSplitParent))
       {
         savedBR = secondSplitParent;
         savedBR->GetParentNode(getter_AddRefs(tmp));
@@ -2854,7 +2867,7 @@ nsHTMLEditRules::IsEmptyBlock(nsIDOMNode *aNode,
   
 //  nsresult res = NS_OK;
   nsCOMPtr nodeToTest;
-  if (nsEditor::IsBlockNode(aNode)) nodeToTest = do_QueryInterface(aNode);
+  if (IsBlockNode(aNode)) nodeToTest = do_QueryInterface(aNode);
 //  else nsCOMPtr block;
 //  looks like I forgot to finish this.  Wonder what I was going to do?
 
@@ -2907,7 +2920,7 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection,
   {
     nsCOMPtr isupports = dont_AddRef(arrayOfNodes->ElementAt(0));
     nsCOMPtr theNode( do_QueryInterface(isupports ) );
-    if (nsHTMLEditUtils::IsBreak(theNode))
+    if (nsTextEditUtils::IsBreak(theNode))
     {
       emptyDiv = PR_TRUE;
     }
@@ -2925,14 +2938,14 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection,
     // creating extra lines, if possible.
     res = mHTMLEditor->GetNextHTMLNode(parent, offset, address_of(brNode));
     if (NS_FAILED(res)) return res;
-    if (brNode && nsHTMLEditUtils::IsBreak(brNode))
+    if (brNode && nsTextEditUtils::IsBreak(brNode))
     {
       // making use of html structure... if next node after where
       // we are putting our div is not a block, then the br we 
       // found is in same block we are, so its safe to consume it.
       res = mHTMLEditor->GetNextHTMLSibling(parent, offset, address_of(sib));
       if (NS_FAILED(res)) return res;
-      if (!nsEditor::IsBlockNode(sib))
+      if (!IsBlockNode(sib))
       {
         res = mHTMLEditor->DeleteNode(brNode);
         if (NS_FAILED(res)) return res;
@@ -3377,20 +3390,20 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt
     // back up through any prior inline nodes that
     // aren't across a 
from us. - if (!nsEditor::IsBlockNode(node)) + if (!IsBlockNode(node)) { - nsCOMPtr block = nsEditor::GetBlockNodeParent(node); + nsCOMPtr block = nsHTMLEditor::GetBlockNodeParent(node); nsCOMPtr prevNode, prevNodeBlock; res = mHTMLEditor->GetPriorHTMLNode(node, address_of(prevNode)); while (prevNode && NS_SUCCEEDED(res)) { - prevNodeBlock = nsEditor::GetBlockNodeParent(prevNode); + prevNodeBlock = nsHTMLEditor::GetBlockNodeParent(prevNode); if (prevNodeBlock != block) break; - if (nsHTMLEditUtils::IsBreak(prevNode)) + if (nsTextEditUtils::IsBreak(prevNode)) break; - if (nsEditor::IsBlockNode(prevNode)) + if (IsBlockNode(prevNode)) break; node = prevNode; res = mHTMLEditor->GetPriorHTMLNode(node, address_of(prevNode)); @@ -3399,11 +3412,11 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt // finding the real start for this point. look up the tree for as long as we are the // first node in the container, and as long as we haven't hit the body node. - if (!nsHTMLEditUtils::IsBody(node)) + if (!nsTextEditUtils::IsBody(node)) { res = nsEditor::GetNodeLocation(node, address_of(parent), &offset); if (NS_FAILED(res)) return res; - while ((IsFirstNode(node)) && (!nsHTMLEditUtils::IsBody(parent))) + while ((IsFirstNode(node)) && (!nsTextEditUtils::IsBody(parent))) { // some cutoffs are here: we don't need to also include them in the aWhere == kEnd case. // as long as they are in one or the other it will work. @@ -3443,23 +3456,23 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt // look ahead through any further inline nodes that // aren't across a
from us, and that are enclosed in the same block. - if (!nsEditor::IsBlockNode(node)) + if (!IsBlockNode(node)) { - nsCOMPtr block = nsEditor::GetBlockNodeParent(node); + nsCOMPtr block = nsHTMLEditor::GetBlockNodeParent(node); nsCOMPtr nextNode, nextNodeBlock; res = mHTMLEditor->GetNextHTMLNode(node, address_of(nextNode)); while (nextNode && NS_SUCCEEDED(res)) { - nextNodeBlock = nsEditor::GetBlockNodeParent(nextNode); + nextNodeBlock = nsHTMLEditor::GetBlockNodeParent(nextNode); if (nextNodeBlock != block) break; - if (nsHTMLEditUtils::IsBreak(nextNode)) + if (nsTextEditUtils::IsBreak(nextNode)) { node = nextNode; break; } - if (nsEditor::IsBlockNode(nextNode)) + if (IsBlockNode(nextNode)) break; node = nextNode; res = mHTMLEditor->GetNextHTMLNode(node, address_of(nextNode)); @@ -3468,11 +3481,11 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt // finding the real end for this point. look up the tree for as long as we are the // last node in the container, and as long as we haven't hit the body node. - if (!nsHTMLEditUtils::IsBody(node)) + if (!nsTextEditUtils::IsBody(node)) { res = nsEditor::GetNodeLocation(node, address_of(parent), &offset); if (NS_FAILED(res)) return res; - while ((IsLastNode(node)) && (!nsHTMLEditUtils::IsBody(parent))) + while ((IsLastNode(node)) && (!nsTextEditUtils::IsBody(parent))) { node = parent; res = nsEditor::GetNodeLocation(node, address_of(parent), &offset); @@ -3708,7 +3721,7 @@ nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges, { isupports = dont_AddRef((*outArrayOfNodes)->ElementAt(i)); nsCOMPtr node( do_QueryInterface(isupports) ); - if (!aDontTouchContent && mHTMLEditor->IsInlineNode(node) + if (!aDontTouchContent && IsInlineNode(node) && mHTMLEditor->IsContainer(node) && !mHTMLEditor->IsTextNode(node)) { nsCOMPtr arrayOfInlines; @@ -4076,10 +4089,10 @@ nsCOMPtr nsHTMLEditRules::GetHighestInlineParent(nsIDOMNode* aNode) { if (!aNode) return nsnull; - if (nsEditor::IsBlockNode(aNode)) return nsnull; + if (IsBlockNode(aNode)) return nsnull; nsCOMPtr inlineNode, node=aNode; - while (node && mHTMLEditor->IsInlineNode(node)) + while (node && IsInlineNode(node)) { inlineNode = node; inlineNode->GetParentNode(getter_AddRefs(node)); @@ -4217,7 +4230,7 @@ nsHTMLEditRules::ReturnInHeader(nsISelection *aSelection, nsCOMPtr sibling; res = mHTMLEditor->GetNextHTMLSibling(headerParent, offset+1, address_of(sibling)); if (NS_FAILED(res)) return res; - if (!sibling || !nsHTMLEditUtils::IsBreak(sibling)) + if (!sibling || !nsTextEditUtils::IsBreak(sibling)) { res = CreateMozBR(headerParent, offset+1, address_of(sibling)); if (NS_FAILED(res)) return res; @@ -4274,8 +4287,8 @@ nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection, // just fall out to default of inserting a BR return res; } - if (nsHTMLEditUtils::IsBreak(sibling) - && !nsHTMLEditUtils::HasMozAttr(sibling)) + if (nsTextEditUtils::IsBreak(sibling) + && !nsTextEditUtils::HasMozAttr(sibling)) { PRInt32 newOffset; *aCancel = PR_TRUE; @@ -4312,8 +4325,8 @@ nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection, // just fall out to default of inserting a BR return res; } - if (nsHTMLEditUtils::IsBreak(sibling) - && !nsHTMLEditUtils::HasMozAttr(sibling)) + if (nsTextEditUtils::IsBreak(sibling) + && !nsTextEditUtils::HasMozAttr(sibling)) { PRInt32 newOffset; *aCancel = PR_TRUE; @@ -4340,14 +4353,14 @@ nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection, nsCOMPtr nearNode; res = mHTMLEditor->GetPriorHTMLNode(aNode, aOffset, address_of(nearNode)); if (NS_FAILED(res)) return res; - if (!nearNode || !nsHTMLEditUtils::IsBreak(nearNode) - || nsHTMLEditUtils::HasMozAttr(nearNode)) + if (!nearNode || !nsTextEditUtils::IsBreak(nearNode) + || nsTextEditUtils::HasMozAttr(nearNode)) { // is there a BR after to it? res = mHTMLEditor->GetNextHTMLNode(aNode, aOffset, address_of(nearNode)); if (NS_FAILED(res)) return res; - if (!nearNode || !nsHTMLEditUtils::IsBreak(nearNode) - || nsHTMLEditUtils::HasMozAttr(nearNode)) + if (!nearNode || !nsTextEditUtils::IsBreak(nearNode) + || nsTextEditUtils::HasMozAttr(nearNode)) { // just fall out to default of inserting a BR return res; @@ -4658,7 +4671,7 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString // arrayOfNodes is contructed, but some additional logic should // be added here if that should change - else if (nsEditor::IsInlineNode(curNode) && !bNoParent) + else if (IsInlineNode(curNode) && !bNoParent) { // if curNode is a non editable, drop it if we are going to
       if ((aBlockTag->EqualsWithConversion("pre")) && (!mHTMLEditor->IsEditable(curNode)))
@@ -4743,9 +4756,9 @@ nsHTMLEditRules::AddTerminatingBR(nsIDOMNode *aBlock)
   if (!aBlock) return NS_ERROR_NULL_POINTER;
   nsCOMPtr last;
   nsresult res = mHTMLEditor->GetLastEditableLeaf(aBlock, address_of(last));
-  if (last && nsHTMLEditUtils::IsBreak(last))
+  if (last && nsTextEditUtils::IsBreak(last))
   {
-    if (nsHTMLEditUtils::IsMozBR(last))
+    if (nsTextEditUtils::IsMozBR(last))
     {
       // need to convert a br
       nsCOMPtr elem = do_QueryInterface(last);
@@ -4872,7 +4885,7 @@ nsHTMLEditRules::GetTopEnclosingMailCite(nsIDOMNode *aNode,
     if ( (aPlainText && nsHTMLEditUtils::IsPre(node)) ||
          (!aPlainText && nsHTMLEditUtils::IsMailCite(node)) )
       *aOutCiteNode = node;
-    if (nsHTMLEditUtils::IsBody(node)) break;
+    if (nsTextEditUtils::IsBody(node)) break;
     
     res = node->GetParentNode(getter_AddRefs(parentNode));
     if (NS_FAILED(res)) return res;
@@ -5021,13 +5034,13 @@ nsHTMLEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection
   
   // is nearNode also a descendant of same block?
   nsCOMPtr block, nearBlock;
-  if (mHTMLEditor->IsBlockNode(selNode)) block = selNode;
+  if (IsBlockNode(selNode)) block = selNode;
   else block = mHTMLEditor->GetBlockNodeParent(selNode);
   nearBlock = mHTMLEditor->GetBlockNodeParent(nearNode);
   if (block == nearBlock)
   {
-    if (nearNode && nsHTMLEditUtils::IsBreak(nearNode)
-        && !nsHTMLEditUtils::IsMozBR(nearNode))
+    if (nearNode && nsTextEditUtils::IsBreak(nearNode)
+        && !nsTextEditUtils::IsMozBR(nearNode))
     {
       PRBool bIsLast;
       res = mHTMLEditor->IsLastEditableChild(nearNode, &bIsLast);
@@ -5058,7 +5071,7 @@ nsHTMLEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection
         if (NS_FAILED(res)) return res;
         res = mHTMLEditor->GetNextHTMLSibling(nearNode, address_of(nextNode));
         if (NS_FAILED(res)) return res;
-        if (nextNode && mHTMLEditor->IsBlockNode(nextNode))
+        if (nextNode && IsBlockNode(nextNode))
         {
           // need to insert special moz BR. Why?  Because if we don't
           // the user will see no new line for the break.  
@@ -5079,12 +5092,12 @@ nsHTMLEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection
   // we aren't in a textnode: are we adjacent to a break or an image?
   res = mHTMLEditor->GetPriorHTMLSibling(selNode, selOffset, address_of(nearNode));
   if (NS_FAILED(res)) return res;
-  if (nearNode && (nsHTMLEditUtils::IsBreak(nearNode)
+  if (nearNode && (nsTextEditUtils::IsBreak(nearNode)
                    || nsHTMLEditUtils::IsImage(nearNode)))
     return NS_OK; // this is a good place for the caret to be
   res = mHTMLEditor->GetNextHTMLSibling(selNode, selOffset, address_of(nearNode));
   if (NS_FAILED(res)) return res;
-  if (nearNode && (nsHTMLEditUtils::IsBreak(nearNode)
+  if (nearNode && (nsTextEditUtils::IsBreak(nearNode)
                    || nsHTMLEditUtils::IsImage(nearNode)))
     return NS_OK; // this is a good place for the caret to be
 
@@ -5136,7 +5149,7 @@ nsHTMLEditRules::FindNearSelectableNode(nsIDOMNode *aSelNode,
   // scan in the right direction until we find an eligible text node,
   // but dont cross any breaks, images, or table elements.
   while (nearNode && !(mHTMLEditor->IsTextNode(nearNode)
-                       || nsHTMLEditUtils::IsBreak(nearNode)
+                       || nsTextEditUtils::IsBreak(nearNode)
                        || nsHTMLEditUtils::IsImage(nearNode)))
   {
     curNode = nearNode;
@@ -5226,7 +5239,7 @@ nsHTMLEditRules::RemoveEmptyNodes()
       PRBool bIsEmptyNode;
       res = mHTMLEditor->IsEmptyNode(node, &bIsEmptyNode, PR_FALSE, PR_TRUE);
       if (NS_FAILED(res)) return res;
-      if (bIsEmptyNode && !nsHTMLEditUtils::IsBody(node))
+      if (bIsEmptyNode && !nsTextEditUtils::IsBody(node))
       {
         if (nsHTMLEditUtils::IsParagraph(node) ||
             nsHTMLEditUtils::IsHeader(node)    ||
@@ -5564,7 +5577,7 @@ nsHTMLEditRules::ConfirmSelectionInBody()
   temp = selNode;
   
   // check that selNode is inside body
-  while (temp && !nsHTMLEditUtils::IsBody(temp))
+  while (temp && !nsTextEditUtils::IsBody(temp))
   {
     res = temp->GetParentNode(getter_AddRefs(parent));
     temp = parent;
@@ -5584,7 +5597,7 @@ nsHTMLEditRules::ConfirmSelectionInBody()
   temp = selNode;
   
   // check that selNode is inside body
-  while (temp && !nsHTMLEditUtils::IsBody(temp))
+  while (temp && !nsTextEditUtils::IsBody(temp))
   {
     res = temp->GetParentNode(getter_AddRefs(parent));
     temp = parent;
@@ -5654,7 +5667,7 @@ nsresult
 nsHTMLEditRules::InsertMozBRIfNeeded(nsIDOMNode *aNode)
 {
   if (!aNode) return NS_ERROR_NULL_POINTER;
-  if (!mHTMLEditor->IsBlockNode(aNode)) return NS_OK;
+  if (!IsBlockNode(aNode)) return NS_OK;
   
   PRBool isEmpty;
   nsCOMPtr brNode;
diff --git a/mozilla/editor/base/nsHTMLEditUtils.cpp b/mozilla/editor/base/nsHTMLEditUtils.cpp
index 97d5201f2ff..7978e5cf12e 100644
--- a/mozilla/editor/base/nsHTMLEditUtils.cpp
+++ b/mozilla/editor/base/nsHTMLEditUtils.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "nsHTMLEditUtils.h"
+#include "nsTextEditUtils.h"
 
 #include "nsString.h"
 #include "nsEditor.h"
@@ -28,124 +29,21 @@
 #include "nsIDOMNodeList.h"
 #include "nsIDOMHTMLAnchorElement.h"
 
-PRBool
-nsHTMLEditUtils::NodeIsType(nsIDOMNode *aNode, const nsAReadableString& aTag)
-{
-  NS_PRECONDITION(aNode, "null node passed to nsHTMLEditUtils::NodeIsType");
-  if (aNode)
-  {
-    nsAutoString tag;
-    nsEditor::GetTagString(aNode,tag);
-    tag.ToLowerCase();
-    if (tag.Equals(aTag))
-      return PR_TRUE;
-  }
-  return PR_FALSE;
-}
-
-/********************************************************
- *  helper methods from nsTextEditRules
- ********************************************************/
- 
 ///////////////////////////////////////////////////////////////////////////
-// IsBody: true if node an html body node
-//                  
-PRBool 
-nsHTMLEditUtils::IsBody(nsIDOMNode *node)
-{
-  return NodeIsType(node, NS_LITERAL_STRING("body"));
-}
-
-
-
-///////////////////////////////////////////////////////////////////////////
-// IsBreak: true if node an html break node
-//                  
-PRBool 
-nsHTMLEditUtils::IsBreak(nsIDOMNode *node)
-{
-  return NodeIsType(node, NS_LITERAL_STRING("br"));
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// IsBreak: true if node an html break node
 //                  
 PRBool 
 nsHTMLEditUtils::IsBig(nsIDOMNode *node)
 {
-  return NodeIsType(node, NS_LITERAL_STRING("big"));
+  return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("big"));
 }
 
 
 ///////////////////////////////////////////////////////////////////////////
-// IsBreak: true if node an html break node
 //                  
 PRBool 
 nsHTMLEditUtils::IsSmall(nsIDOMNode *node)
 {
-  return NodeIsType(node, NS_LITERAL_STRING("small"));
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// IsMozBR: true if node an html br node with type = _moz
-//                  
-PRBool 
-nsHTMLEditUtils::IsMozBR(nsIDOMNode *node)
-{
-  NS_PRECONDITION(node, "null node passed to nsHTMLEditUtils::IsMozBR");
-  if (IsBreak(node) && HasMozAttr(node)) return PR_TRUE;
-  return PR_FALSE;
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// HasMozAttr: true if node has type attribute = _moz
-//             (used to indicate the div's and br's we use in
-//              mail compose rules)
-//                  
-PRBool 
-nsHTMLEditUtils::HasMozAttr(nsIDOMNode *node)
-{
-  NS_PRECONDITION(node, "null parent passed to nsHTMLEditUtils::HasMozAttr");
-  nsCOMPtr elem = do_QueryInterface(node);
-  if (elem)
-  {
-    nsAutoString typeAttrName; typeAttrName.AssignWithConversion("type");
-    nsAutoString typeAttrVal;
-    nsresult res = elem->GetAttribute(typeAttrName, typeAttrVal);
-    typeAttrVal.ToLowerCase();
-    if (NS_SUCCEEDED(res) && (typeAttrVal.EqualsWithConversion("_moz")))
-      return PR_TRUE;
-  }
-  return PR_FALSE;
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// InBody: true if node is a descendant of the body
-//                  
-PRBool 
-nsHTMLEditUtils::InBody(nsIDOMNode *node, nsIEditor *editor)
-{
-  if ( node )
-  {
-    nsCOMPtr bodyElement;
-    nsresult res = editor->GetRootElement(getter_AddRefs(bodyElement));
-    if (NS_FAILED(res) || !bodyElement)
-      return res?res:NS_ERROR_NULL_POINTER;
-    nsCOMPtr bodyNode = do_QueryInterface(bodyElement);
-    nsCOMPtr tmp;
-    nsCOMPtr p = node;
-    while (p && p!= bodyNode)
-    {
-      if (NS_FAILED(p->GetParentNode(getter_AddRefs(tmp))) || !tmp)
-        return PR_FALSE;
-      p = tmp;
-    }
-  }
-  return PR_TRUE;
+  return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("small"));
 }
 
 
@@ -182,7 +80,7 @@ nsHTMLEditUtils::IsHeader(nsIDOMNode *node)
 PRBool 
 nsHTMLEditUtils::IsParagraph(nsIDOMNode *node)
 {
-  return NodeIsType(node, NS_LITERAL_STRING("p"));
+  return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("p"));
 }
 
 
@@ -232,7 +130,7 @@ nsHTMLEditUtils::IsTableElement(nsIDOMNode *node)
 PRBool 
 nsHTMLEditUtils::IsTable(nsIDOMNode *node)
 {
-  return NodeIsType(node, NS_LITERAL_STRING("table"));
+  return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("table"));
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -241,7 +139,7 @@ nsHTMLEditUtils::IsTable(nsIDOMNode *node)
 PRBool 
 nsHTMLEditUtils::IsTableRow(nsIDOMNode *node)
 {
-  return NodeIsType(node, NS_LITERAL_STRING("tr"));
+  return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("tr"));
 }
 
 
@@ -309,7 +207,7 @@ nsHTMLEditUtils::IsList(nsIDOMNode *node)
 PRBool 
 nsHTMLEditUtils::IsOrderedList(nsIDOMNode *node)
 {
-  return NodeIsType(node, NS_LITERAL_STRING("ol"));
+  return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("ol"));
 }
 
 
@@ -319,7 +217,7 @@ nsHTMLEditUtils::IsOrderedList(nsIDOMNode *node)
 PRBool 
 nsHTMLEditUtils::IsUnorderedList(nsIDOMNode *node)
 {
-  return NodeIsType(node, NS_LITERAL_STRING("ul"));
+  return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("ul"));
 }
 
 
@@ -329,7 +227,7 @@ nsHTMLEditUtils::IsUnorderedList(nsIDOMNode *node)
 PRBool 
 nsHTMLEditUtils::IsDefinitionList(nsIDOMNode *node)
 {
-  return NodeIsType(node, NS_LITERAL_STRING("dl"));
+  return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("dl"));
 }
 
 
@@ -339,7 +237,7 @@ nsHTMLEditUtils::IsDefinitionList(nsIDOMNode *node)
 PRBool 
 nsHTMLEditUtils::IsBlockquote(nsIDOMNode *node)
 {
-  return NodeIsType(node, NS_LITERAL_STRING("blockquote"));
+  return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("blockquote"));
 }
 
 
@@ -349,7 +247,7 @@ nsHTMLEditUtils::IsBlockquote(nsIDOMNode *node)
 PRBool 
 nsHTMLEditUtils::IsPre(nsIDOMNode *node)
 {
-  return NodeIsType(node, NS_LITERAL_STRING("pre"));
+  return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("pre"));
 }
 
 
@@ -359,7 +257,7 @@ nsHTMLEditUtils::IsPre(nsIDOMNode *node)
 PRBool 
 nsHTMLEditUtils::IsAddress(nsIDOMNode *node)
 {
-  return NodeIsType(node, NS_LITERAL_STRING("address"));
+  return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("address"));
 }
 
 
@@ -369,7 +267,7 @@ nsHTMLEditUtils::IsAddress(nsIDOMNode *node)
 PRBool 
 nsHTMLEditUtils::IsAnchor(nsIDOMNode *node)
 {
-  return NodeIsType(node, NS_LITERAL_STRING("a"));
+  return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("a"));
 }
 
 
@@ -379,7 +277,7 @@ nsHTMLEditUtils::IsAnchor(nsIDOMNode *node)
 PRBool 
 nsHTMLEditUtils::IsImage(nsIDOMNode *node)
 {
-  return NodeIsType(node, NS_LITERAL_STRING("img"));
+  return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("img"));
 }
 
 PRBool 
@@ -417,7 +315,7 @@ nsHTMLEditUtils::IsNamedAnchor(nsIDOMNode *aNode)
 PRBool 
 nsHTMLEditUtils::IsDiv(nsIDOMNode *node)
 {
-  return NodeIsType(node, NS_LITERAL_STRING("div"));
+  return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("div"));
 }
 
 
@@ -427,7 +325,7 @@ nsHTMLEditUtils::IsDiv(nsIDOMNode *node)
 PRBool 
 nsHTMLEditUtils::IsNormalDiv(nsIDOMNode *node)
 {
-  if (IsDiv(node) && !nsHTMLEditUtils::HasMozAttr(node)) return PR_TRUE;
+  if (IsDiv(node) && !nsTextEditUtils::HasMozAttr(node)) return PR_TRUE;
   return PR_FALSE;
 }
 
@@ -438,7 +336,7 @@ nsHTMLEditUtils::IsNormalDiv(nsIDOMNode *node)
 PRBool 
 nsHTMLEditUtils::IsMozDiv(nsIDOMNode *node)
 {
-  if (IsDiv(node) && HasMozAttr(node)) return PR_TRUE;
+  if (IsDiv(node) && nsTextEditUtils::HasMozAttr(node)) return PR_TRUE;
   return PR_FALSE;
 }
 
@@ -474,7 +372,7 @@ nsHTMLEditUtils::IsMailCite(nsIDOMNode *node)
 PRBool 
 nsHTMLEditUtils::IsTextarea(nsIDOMNode *node)
 {
-  return NodeIsType(node, NS_LITERAL_STRING("textarea"));
+  return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("textarea"));
 }
 
 
@@ -484,7 +382,7 @@ nsHTMLEditUtils::IsTextarea(nsIDOMNode *node)
 PRBool 
 nsHTMLEditUtils::IsMap(nsIDOMNode *node)
 {
-  return NodeIsType(node, NS_LITERAL_STRING("map"));
+  return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("map"));
 }
 
 
diff --git a/mozilla/editor/base/nsHTMLEditUtils.h b/mozilla/editor/base/nsHTMLEditUtils.h
index f7ed2f0b58e..e644c7d72ed 100644
--- a/mozilla/editor/base/nsHTMLEditUtils.h
+++ b/mozilla/editor/base/nsHTMLEditUtils.h
@@ -25,23 +25,15 @@
 
 #include "prtypes.h"  // for PRBool
 #include "nsError.h"  // for nsresult
-#include "nsString.h" // for nsAReadableString
 class nsIEditor;
 class nsIDOMNode;
 
 class nsHTMLEditUtils
 {
 public:
-  static PRBool NodeIsType(nsIDOMNode *aNode, const nsAReadableString& aTag);
-
   // from nsTextEditRules:
-  static PRBool IsBody(nsIDOMNode *aNode);
-  static PRBool IsBreak(nsIDOMNode *aNode);
   static PRBool IsBig(nsIDOMNode *aNode);
   static PRBool IsSmall(nsIDOMNode *aNode);
-  static PRBool IsMozBR(nsIDOMNode *aNode);
-  static PRBool HasMozAttr(nsIDOMNode *aNode);
-  static PRBool InBody(nsIDOMNode *aNode, nsIEditor *aEditor);
 
   // from nsHTMLEditRules:
   static PRBool IsHeader(nsIDOMNode *aNode);
diff --git a/mozilla/editor/base/nsHTMLEditor.cpp b/mozilla/editor/base/nsHTMLEditor.cpp
index 0f41f4aeadf..b9c5d507ec5 100644
--- a/mozilla/editor/base/nsHTMLEditor.cpp
+++ b/mozilla/editor/base/nsHTMLEditor.cpp
@@ -25,9 +25,11 @@
 
 #include "nsHTMLEditor.h"
 #include "nsHTMLEditRules.h"
+#include "nsTextEditUtils.h"
 #include "nsHTMLEditUtils.h"
 
 #include "nsEditorEventListeners.h"
+#include "TypeInState.h"
 
 #include "nsIDOMText.h"
 #include "nsIDOMNodeList.h"
@@ -45,6 +47,8 @@
 #include "nsIDOMHTMLImageElement.h"
 #include "nsISelectionController.h"
 
+#include "TransactionFactory.h"
+
 #include "nsIIndependentSelection.h" //domselections answer to frameselection
 
 #include "nsICSSLoader.h"
@@ -74,13 +78,12 @@
 #include "nsIDOMDocumentFragment.h"
 #include "nsIPresShell.h"
 #include "nsIPresContext.h"
-#include "nsIParser.h"
 #include "nsParserCIID.h"
+#include "nsIParserService.h"
 #include "nsIImage.h"
 #include "nsAOLCiter.h"
 #include "nsInternetCiter.h"
 #include "nsISupportsPrimitives.h"
-#include "InsertTextTxn.h"
 #include "SetDocTitleTxn.h"
 
 // netwerk
@@ -95,7 +98,6 @@
 #include "nsIDOMNSUIEvent.h"
 
 // Transactionas
-#include "PlaceholderTxn.h"
 #include "nsStyleSheetTxns.h"
 
 // Misc
@@ -103,8 +105,6 @@
 #include "nsEditorUtils.h"
 #include "nsIPref.h"
 
-const PRUnichar nbsp = 160;
-
 // HACK - CID for NS_CTRANSITIONAL_DTD_CID so that we can get at transitional dtd
 #define NS_CTRANSITIONAL_DTD_CID \
 { 0x4611d482, 0x960a, 0x11d4, { 0x8e, 0xb0, 0xb6, 0x17, 0x66, 0x1b, 0x6f, 0x7c } }
@@ -116,8 +116,7 @@ static NS_DEFINE_IID(kSubtreeIteratorCID, NS_SUBTREEITERATOR_CID);
 static NS_DEFINE_CID(kCRangeCID,      NS_RANGE_CID);
 static NS_DEFINE_CID(kCDOMSelectionCID,      NS_DOMSELECTION_CID);
 static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
-static NS_DEFINE_IID(kCParserIID, NS_IPARSER_IID); 
-static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID); 
+static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
 static NS_DEFINE_CID(kCTransitionalDTDCID,  NS_CTRANSITIONAL_DTD_CID);
 
 #if defined(NS_DEBUG) && defined(DEBUG_buster)
@@ -232,7 +231,12 @@ NS_IMETHODIMP nsHTMLEditor::Init(nsIDOMDocument *aDoc,
     return NS_ERROR_NULL_POINTER;
 
   nsresult result = NS_OK, rulesRes = NS_OK;
-  
+
+  // Init mEditProperty
+  result = NS_NewEditProperty(getter_AddRefs(mEditProperty));
+  if (NS_FAILED(result)) { return result; }
+  if (!mEditProperty) {return NS_ERROR_NULL_POINTER;}
+
   if (1)
   {
     // block to scope nsAutoEditInitRulesTrigger
@@ -416,6 +420,117 @@ NS_IMETHODIMP nsHTMLEditor::InitRules()
   return res;
 }
 
+/**
+ * Returns true if the id represents an element of block type.
+ * Can be used to determine if a new paragraph should be started.
+ */
+nsresult
+nsHTMLEditor::NodeIsBlockStatic(nsIDOMNode *aNode, PRBool &aIsBlock)
+{
+  if (!aNode) { return NS_ERROR_NULL_POINTER; }
+
+  nsresult rv;
+
+  nsCOMPtrelement;
+  element = do_QueryInterface(aNode);
+  if (!element)
+  {
+    // We don't have an element -- probably a text node
+    aIsBlock = PR_FALSE;
+    return NS_OK;
+  }
+
+  aIsBlock = PR_FALSE;
+
+  // Get the node name and atom:
+  nsAutoString tagName;
+  rv = element->GetTagName(tagName);
+  if (NS_FAILED(rv)) return rv;
+
+  tagName.ToLowerCase();
+  nsCOMPtr tagAtom = NS_NewAtom(tagName);
+  if (!tagAtom) return NS_ERROR_NULL_POINTER;
+
+  static nsCOMPtr sParserService;
+  if (!sParserService) {
+    sParserService = do_GetService(kParserServiceCID, &rv);
+    if (NS_FAILED(rv)) return rv;
+  }
+
+  // Nodes we know we want to treat as block
+  // even though the parser says they're not:
+  if (tagAtom==nsIEditProperty::body       ||
+      tagAtom==nsIEditProperty::tbody      ||
+      tagAtom==nsIEditProperty::thead      ||
+      tagAtom==nsIEditProperty::tfoot      ||
+      tagAtom==nsIEditProperty::tr         ||
+      tagAtom==nsIEditProperty::th         ||
+      tagAtom==nsIEditProperty::td         ||
+      tagAtom==nsIEditProperty::pre)
+  {
+    aIsBlock = PR_TRUE;
+    return NS_OK;
+  }
+
+  // This sucks.  The parser service's isBlock requires a string,
+  // so we have to get the name atom, convert it into a string, call
+  // the parser service to get the id, in order to call the parser
+  // service to ask about blockness.
+  // Harish is working on a more efficient API we can use.
+  PRInt32 id;
+  rv = sParserService->HTMLStringTagToId(tagName, &id);
+  if (NS_FAILED(rv)) return rv;
+  rv = sParserService->IsBlock(id, aIsBlock);
+
+#ifdef DEBUG
+  // Check this against what we would have said with the old code:
+  if (tagAtom==nsIEditProperty::p          ||
+      tagAtom==nsIEditProperty::div        ||
+      tagAtom==nsIEditProperty::blockquote ||
+      tagAtom==nsIEditProperty::h1         ||
+      tagAtom==nsIEditProperty::h2         ||
+      tagAtom==nsIEditProperty::h3         ||
+      tagAtom==nsIEditProperty::h4         ||
+      tagAtom==nsIEditProperty::h5         ||
+      tagAtom==nsIEditProperty::h6         ||
+      tagAtom==nsIEditProperty::ul         ||
+      tagAtom==nsIEditProperty::ol         ||
+      tagAtom==nsIEditProperty::dl         ||
+      tagAtom==nsIEditProperty::noscript   ||
+      tagAtom==nsIEditProperty::form       ||
+      tagAtom==nsIEditProperty::hr         ||
+      tagAtom==nsIEditProperty::table      ||
+      tagAtom==nsIEditProperty::fieldset   ||
+      tagAtom==nsIEditProperty::address    ||
+      tagAtom==nsIEditProperty::caption    ||
+      tagAtom==nsIEditProperty::col        ||
+      tagAtom==nsIEditProperty::colgroup   ||
+      tagAtom==nsIEditProperty::li         ||
+      tagAtom==nsIEditProperty::dt         ||
+      tagAtom==nsIEditProperty::dd         ||
+      tagAtom==nsIEditProperty::legend     )
+  {
+    if (!aIsBlock)
+    {
+      nsAutoString assertmsg (NS_LITERAL_STRING("Parser and editor disagree on blockness: "));
+      assertmsg.Append(tagName);
+      char* assertstr = assertmsg.ToNewCString();
+      NS_ASSERTION(aIsBlock, assertstr);
+      Recycle(assertstr);
+    }
+  }
+#endif /* DEBUG */
+
+  return rv;
+}
+
+// Non-static version for the nsIEditor interface and JavaScript
+NS_IMETHODIMP 
+nsHTMLEditor::NodeIsBlock(nsIDOMNode *aNode, PRBool &aIsBlock)
+{
+  return NodeIsBlockStatic(aNode, aIsBlock);
+}
+
 NS_IMETHODIMP 
 nsHTMLEditor::SetDocumentTitle(const PRUnichar *aTitle)
 {
@@ -436,6 +551,427 @@ nsHTMLEditor::SetDocumentTitle(const PRUnichar *aTitle)
   return result;
 }
 
+/* ------------ Block methods moved from nsEditor -------------- */
+///////////////////////////////////////////////////////////////////////////
+// GetBlockNodeParent: returns enclosing block level ancestor, if any
+//
+nsCOMPtr
+nsHTMLEditor::GetBlockNodeParent(nsIDOMNode *aNode)
+{
+  nsCOMPtr tmp;
+  nsCOMPtr p;
+
+  if (!aNode)
+  {
+    NS_NOTREACHED("null node passed to GetBlockNodeParent()");
+    return PR_FALSE;
+  }
+
+  if (NS_FAILED(aNode->GetParentNode(getter_AddRefs(p))))  // no parent, ran off top of tree
+    return tmp;
+
+  while (p)
+  {
+    PRBool isBlock;
+    if (NS_FAILED(NodeIsBlockStatic(p, isBlock)) || isBlock)
+      break;
+    if ( NS_FAILED(p->GetParentNode(getter_AddRefs(tmp))) || !tmp) // no parent, ran off top of tree
+      return p;
+
+    p = tmp;
+  }
+  return p;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// HasSameBlockNodeParent: true if nodes have same block level ancestor
+//               
+PRBool
+nsHTMLEditor::HasSameBlockNodeParent(nsIDOMNode *aNode1, nsIDOMNode *aNode2)
+{
+  if (!aNode1 || !aNode2)
+  {
+    NS_NOTREACHED("null node passed to HasSameBlockNodeParent()");
+    return PR_FALSE;
+  }
+  
+  if (aNode1 == aNode2)
+    return PR_TRUE;
+    
+  nsCOMPtr p1 = GetBlockNodeParent(aNode1);
+  nsCOMPtr p2 = GetBlockNodeParent(aNode2);
+
+  return (p1 == p2);
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// GetBlockSection: return leftmost/rightmost nodes in aChild's block
+//               
+nsresult
+nsHTMLEditor::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 isBlock;
+    NodeIsBlockStatic(sibling, isBlock);
+    if (isBlock)
+    {
+      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 isBlock;
+    NodeIsBlockStatic(sibling, isBlock);
+    if (isBlock) 
+    {
+      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", 
+                       (void*)(*aLeftNode), (void*)(*aRightNode)); }
+
+  return result;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// GetBlockSectionsForRange: return list of block sections that intersect 
+//                           this range
+nsresult
+nsHTMLEditor::GetBlockSectionsForRange(nsIDOMRange *aRange,
+                                       nsISupportsArray *aSections) 
+{
+  if (!aRange || !aSections) {return NS_ERROR_NULL_POINTER;}
+
+  nsresult result;
+  nsCOMPtriter;
+  result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
+                                              NS_GET_IID(nsIContentIterator), getter_AddRefs(iter));
+  if ((NS_SUCCEEDED(result)) && iter)
+  {
+    nsCOMPtr lastRange;
+    iter->Init(aRange);
+    nsCOMPtr currentContent;
+    iter->CurrentNode(getter_AddRefs(currentContent));
+    while (NS_ENUMERATOR_FALSE == 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.get()) + { + lastRange = do_QueryInterface(nsnull); + } + else + { + PRBool isNotInlineOrText; + result = NodeIsBlockStatic(currentNode, isNotInlineOrText); + if (isNotInlineOrText) + { + PRUint16 nodeType; + currentNode->GetNodeType(&nodeType); + if (nsIDOMNode::TEXT_NODE == nodeType) { + isNotInlineOrText = PR_TRUE; + } + } + if (PR_FALSE==isNotInlineOrText) + { + nsCOMPtrleftNode; + nsCOMPtrrightNode; + result = GetBlockSection(currentNode, + getter_AddRefs(leftNode), + getter_AddRefs(rightNode)); + if (gNoisy) {printf("currentNode %p has block content (%p,%p)\n", (void*)currentNode.get(), (void*)leftNode.get(), (void*)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->GetStartContainer(getter_AddRefs(lastStartNode)); + blockParentOfLastStartNode = do_QueryInterface(GetBlockNodeParent(lastStartNode)); + if (blockParentOfLastStartNode) + { + if (gNoisy) {printf("lastStartNode %p has block parent %p\n", (void*)lastStartNode.get(), (void*)blockParentOfLastStartNode.get());} + nsCOMPtr blockParentOfLeftNode; + blockParentOfLeftNode = do_QueryInterface(GetBlockNodeParent(leftNode)); + if (blockParentOfLeftNode) + { + if (gNoisy) {printf("leftNode %p has block parent %p\n", (void*)leftNode.get(), (void*)blockParentOfLeftNode.get());} + if (blockParentOfLastStartNode==blockParentOfLeftNode) { + addRange = PR_FALSE; + } + } + } + } + if (PR_TRUE==addRange) + { + if (gNoisy) {printf("adding range, setting lastRange with start node %p\n", (void*)leftNode.get());} + nsCOMPtr range; + result = nsComponentManager::CreateInstance(kCRangeCID, nsnull, + NS_GET_IID(nsIDOMRange), 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; +} + + +/////////////////////////////////////////////////////////////////////////// +// NextNodeInBlock: gets the next/prev node in the block, if any. Next node +// must be an element or text node, others are ignored +nsCOMPtr +nsHTMLEditor::NextNodeInBlock(nsIDOMNode *aNode, IterDirection aDir) +{ + nsCOMPtr nullNode; + nsCOMPtr content; + nsCOMPtr blockContent; + nsCOMPtr node; + nsCOMPtr blockParent; + + if (!aNode) return nullNode; + + nsCOMPtr iter; + if (NS_FAILED(nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull, + NS_GET_IID(nsIContentIterator), + getter_AddRefs(iter)))) + return nullNode; + + // much gnashing of teeth as we twit back and forth between content and domnode types + content = do_QueryInterface(aNode); + PRBool isBlock; + if (NS_SUCCEEDED(NodeIsBlockStatic(aNode, isBlock)) && isBlock) + { + blockParent = do_QueryInterface(aNode); + } + else + { + blockParent = GetBlockNodeParent(aNode); + } + if (!blockParent) return nullNode; + blockContent = do_QueryInterface(blockParent); + if (!blockContent) return nullNode; + + if (NS_FAILED(iter->Init(blockContent))) return nullNode; + if (NS_FAILED(iter->PositionAt(content))) return nullNode; + + while (NS_ENUMERATOR_FALSE == iter->IsDone()) + { + if (NS_FAILED(iter->CurrentNode(getter_AddRefs(content)))) return nullNode; + // ignore nodes that aren't elements or text, or that are the block parent + node = do_QueryInterface(content); + if (node && IsTextOrElementNode(node) && (node != blockParent) && (node.get() != aNode)) + return node; + + if (aDir == kIterForward) + iter->Next(); + else + iter->Prev(); + } + + return nullNode; +} + +static const PRUnichar nbsp = 160; + +/////////////////////////////////////////////////////////////////////////// +// IsNextCharWhitespace: checks the adjacent content in the same block +// to see if following selection is whitespace or nbsp +nsresult +nsHTMLEditor::IsNextCharWhitespace(nsIDOMNode *aParentNode, + PRInt32 aOffset, + PRBool *outIsSpace, + PRBool *outIsNBSP, + nsCOMPtr *outNode, + PRInt32 *outOffset) +{ + if (!outIsSpace || !outIsNBSP) return NS_ERROR_NULL_POINTER; + *outIsSpace = PR_FALSE; + *outIsNBSP = PR_FALSE; + if (outNode) *outNode = nsnull; + if (outOffset) *outOffset = -1; + + nsAutoString tempString; + PRUint32 strLength; + nsCOMPtr textNode = do_QueryInterface(aParentNode); + if (textNode) + { + textNode->GetLength(&strLength); + if ((PRUint32)aOffset < strLength) + { + // easy case: next char is in same node + textNode->SubstringData(aOffset,aOffset+1,tempString); + *outIsSpace = nsCRT::IsAsciiSpace(tempString.First()); + *outIsNBSP = (tempString.First() == nbsp); + if (outNode) *outNode = do_QueryInterface(aParentNode); + if (outOffset) *outOffset = aOffset+1; // yes, this is _past_ the character; + return NS_OK; + } + } + + // harder case: next char in next node. + nsCOMPtr node = NextNodeInBlock(aParentNode, kIterForward); + nsCOMPtr tmp; + while (node) + { + PRBool isBlock (PR_FALSE); + NodeIsBlock(node, isBlock); + if (isBlock) // skip over bold, italic, link, ect nodes + { + if (IsTextNode(node) && IsEditable(node)) + { + textNode = do_QueryInterface(node); + textNode->GetLength(&strLength); + if (strLength) + { + textNode->SubstringData(0,1,tempString); + *outIsSpace = nsCRT::IsAsciiSpace(tempString.First()); + *outIsNBSP = (tempString.First() == nbsp); + if (outNode) *outNode = do_QueryInterface(node); + if (outOffset) *outOffset = 1; // yes, this is _past_ the character; + return NS_OK; + } + // else it's an empty text node, or not editable; skip it. + } + else // node is an image or some other thingy that doesn't count as whitespace + { + break; + } + } + tmp = node; + node = NextNodeInBlock(tmp, kIterForward); + } + + return NS_OK; +} + + +/////////////////////////////////////////////////////////////////////////// +// IsPrevCharWhitespace: checks the adjacent content in the same block +// to see if following selection is whitespace +nsresult +nsHTMLEditor::IsPrevCharWhitespace(nsIDOMNode *aParentNode, + PRInt32 aOffset, + PRBool *outIsSpace, + PRBool *outIsNBSP, + nsCOMPtr *outNode, + PRInt32 *outOffset) +{ + if (!outIsSpace || !outIsNBSP) return NS_ERROR_NULL_POINTER; + *outIsSpace = PR_FALSE; + *outIsNBSP = PR_FALSE; + if (outNode) *outNode = nsnull; + if (outOffset) *outOffset = -1; + + nsAutoString tempString; + PRUint32 strLength; + nsCOMPtr textNode = do_QueryInterface(aParentNode); + if (textNode) + { + if (aOffset > 0) + { + // easy case: prev char is in same node + textNode->SubstringData(aOffset-1,aOffset,tempString); + *outIsSpace = nsCRT::IsAsciiSpace(tempString.First()); + *outIsNBSP = (tempString.First() == nbsp); + if (outNode) *outNode = do_QueryInterface(aParentNode); + if (outOffset) *outOffset = aOffset-1; + return NS_OK; + } + } + + // harder case: prev char in next node + nsCOMPtr node = NextNodeInBlock(aParentNode, kIterBackward); + nsCOMPtr tmp; + while (node) + { + PRBool isBlock (PR_FALSE); + NodeIsBlock(node, isBlock); + if (isBlock) // skip over bold, italic, link, ect nodes + { + if (IsTextNode(node) && IsEditable(node)) + { + textNode = do_QueryInterface(node); + textNode->GetLength(&strLength); + if (strLength) + { + // you could use nsITextContent::IsOnlyWhitespace here + textNode->SubstringData(strLength-1,strLength,tempString); + *outIsSpace = nsCRT::IsAsciiSpace(tempString.First()); + *outIsNBSP = (tempString.First() == nbsp); + if (outNode) *outNode = do_QueryInterface(aParentNode); + if (outOffset) *outOffset = strLength-1; + return NS_OK; + } + // else it's an empty text node, or not editable; skip it. + } + else // node is an image or some other thingy that doesn't count as whitespace + { + break; + } + } + // otherwise we found a node we want to skip, keep going + tmp = node; + node = NextNodeInBlock(tmp, kIterBackward); + } + + return NS_OK; + +} + + + +/* ------------ End Block methods -------------- */ + + PRBool nsHTMLEditor::IsModifiable() { PRUint32 flags; @@ -482,8 +1018,10 @@ NS_IMETHODIMP nsHTMLEditor::HandleKeyPress(nsIDOMKeyEvent* aKeyEvent) res = GetStartNodeAndOffset(selection, address_of(node), &offset); if (NS_FAILED(res)) return res; if (!node) return NS_ERROR_FAILURE; - - if (IsBlockNode(node)) blockParent = node; + + PRBool isBlock (PR_FALSE); + NodeIsBlock(node, isBlock); + if (isBlock) blockParent = node; else blockParent = GetBlockNodeParent(node); if (blockParent) @@ -1171,7 +1709,7 @@ nsHTMLEditor::InsertNodeAtPoint(nsIDOMNode *aNode, { // If the current parent is a root (body or table element) // then go no further - we can't insert - if (nsHTMLEditUtils::IsBody(parent) || nsHTMLEditUtils::IsTableElement(parent)) + if (nsTextEditUtils::IsBody(parent) || nsHTMLEditUtils::IsTableElement(parent)) return NS_ERROR_FAILURE; // Get the next parent parent->GetParentNode(getter_AddRefs(tmp)); @@ -1311,7 +1849,9 @@ nsHTMLEditor::GetParentBlockTags(nsStringArray *aTagList, PRBool aGetLists) } else { - if (IsBlockNode(node)) blockParent = node; + PRBool isBlock (PR_FALSE); + NodeIsBlock(node, isBlock); + if (isBlock) blockParent = node; else blockParent = GetBlockNodeParent(node); blockParentElem = do_QueryInterface(blockParent); } @@ -1427,7 +1967,7 @@ nsHTMLEditor::GetBackgroundColorState(PRBool &aMixed, nsString &aOutColor) return NS_OK; // Once we hit the body, we're done - if(nsHTMLEditUtils::IsBody(element)) return NS_OK; + if(nsTextEditUtils::IsBody(element)) return NS_OK; // No color is set, but we need to report visible color inherited // from nested cells/tables, so search up parent chain @@ -2878,7 +3418,6 @@ nsHTMLEditor::EndOperation() return res; } - PRBool nsHTMLEditor::TagCanContainTag(const nsString &aParentTag, const nsString &aChildTag) { @@ -3090,7 +3629,7 @@ void nsHTMLEditor::IsTextStyleSet(nsIStyleContext *aSC, PRBool nsHTMLEditor::IsElementInBody(nsIDOMElement* aElement) { - return nsHTMLEditUtils::InBody(aElement, this); + return nsTextEditUtils::InBody(aElement, this); } PRBool @@ -3534,7 +4073,7 @@ nsHTMLEditor::GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr *outNode if (NS_FAILED(res)) return res; // if it's not in the body, then zero it out - if (*outNode && !nsHTMLEditUtils::InBody(*outNode, this)) + if (*outNode && !nsTextEditUtils::InBody(*outNode, this)) { *outNode = nsnull; } @@ -3553,7 +4092,7 @@ nsHTMLEditor::GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr< if (NS_FAILED(res)) return res; // if it's not in the body, then zero it out - if (*outNode && !nsHTMLEditUtils::InBody(*outNode, this)) + if (*outNode && !nsTextEditUtils::InBody(*outNode, this)) { *outNode = nsnull; } @@ -3573,7 +4112,7 @@ nsHTMLEditor::GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr *outNode) if (NS_FAILED(res)) return res; // if it's not in the body, then zero it out - if (*outNode && !nsHTMLEditUtils::InBody(*outNode, this)) + if (*outNode && !nsTextEditUtils::InBody(*outNode, this)) { *outNode = nsnull; } @@ -3592,7 +4131,7 @@ nsHTMLEditor::GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr @@ -54,7 +56,6 @@ class nsIDocumentEncoder; */ class nsHTMLEditor : public nsPlaintextEditor, public nsIHTMLEditor, - public nsIEditorMailSupport, public nsITableEditor, public nsIEditorStyleSheets, public nsICSSLoaderObserver @@ -244,11 +245,67 @@ public: // aTitle may be null or empty string to remove child contents of NS_IMETHOD SetDocumentTitle(const PRUnichar *aTitle); + /* ------------ Block methods moved from nsEditor -------------- */ + static nsCOMPtr<nsIDOMNode> GetBlockNodeParent(nsIDOMNode *aNode); + static PRBool HasSameBlockNodeParent(nsIDOMNode *aNode1, nsIDOMNode *aNode2); + /** Determines the bounding nodes for the block section containing aNode. + * The calculation is based on some nodes intrinsically being block elements + * acording to HTML. Style sheets are not considered in this calculation. + * <BR> tags separate block content sections. So the HTML markup: + * <PRE> + * <P>text1<BR>text2<B>text3</B></P> + * </PRE> + * contains two block content sections. The first has the text node "text1" + * for both endpoints. The second has "text2" as the left endpoint and + * "text3" as the right endpoint. + * Notice that offsets aren't required, only leaf nodes. Offsets are implicit. + * + * @param aNode the block content returned includes aNode + * @param aLeftNode [OUT] the left endpoint of the block content containing aNode + * @param aRightNode [OUT] the right endpoint of the block content containing aNode + * + */ + static nsresult GetBlockSection(nsIDOMNode *aNode, + nsIDOMNode **aLeftNode, + nsIDOMNode **aRightNode); + + /** Compute the set of block sections in a given range. + * A block section is the set of (leftNode, rightNode) pairs given + * by GetBlockSection. The set is computed by computing the + * block section for every leaf node in the range and throwing + * out duplicates. + * + * @param aRange The range to compute block sections for. + * @param aSections Allocated storage for the resulting set, stored as nsIDOMRanges. + */ + static nsresult GetBlockSectionsForRange(nsIDOMRange *aRange, + nsISupportsArray *aSections); + + static nsCOMPtr<nsIDOMNode> NextNodeInBlock(nsIDOMNode *aNode, IterDirection aDir); + nsresult IsNextCharWhitespace(nsIDOMNode *aParentNode, + PRInt32 aOffset, + PRBool *outIsSpace, + PRBool *outIsNBSP, + nsCOMPtr<nsIDOMNode> *outNode = 0, + PRInt32 *outOffset = 0); + nsresult IsPrevCharWhitespace(nsIDOMNode *aParentNode, + PRInt32 aOffset, + PRBool *outIsSpace, + PRBool *outIsNBSP, + nsCOMPtr<nsIDOMNode> *outNode = 0, + PRInt32 *outOffset = 0); + /* ------------ Overrides of nsEditor interface methods -------------- */ /** prepare the editor for use */ NS_IMETHOD Init(nsIDOMDocument *aDoc, nsIPresShell *aPresShell, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags); + /** Internal, static version */ + static nsresult NodeIsBlockStatic(nsIDOMNode *aNode, PRBool &aIsBlock); + + /** This version is for exposure to JavaScript */ + NS_IMETHOD NodeIsBlock(nsIDOMNode *aNode, PRBool &aIsBlock); + /** we override this here to install event listeners */ NS_IMETHOD PostCreate(); @@ -595,6 +652,9 @@ protected: nsCOMPtr<nsIAtom> mUnderlineAtom; nsCOMPtr<nsIAtom> mFontAtom; nsCOMPtr<nsIAtom> mLinkAtom; + + nsCOMPtr<nsIEditProperty> mEditProperty; + nsCOMPtr<nsIDOMNode> mCachedNode; PRBool mCachedBoldStyle; diff --git a/mozilla/editor/base/nsHTMLEditorStyle.cpp b/mozilla/editor/base/nsHTMLEditorStyle.cpp index 8e034d050ee..b17f5ff0e1b 100644 --- a/mozilla/editor/base/nsHTMLEditorStyle.cpp +++ b/mozilla/editor/base/nsHTMLEditorStyle.cpp @@ -22,6 +22,7 @@ #include "nsHTMLEditor.h" #include "nsHTMLEditRules.h" +#include "nsTextEditUtils.h" #include "nsHTMLEditUtils.h" #include "nsEditorEventListeners.h" @@ -50,6 +51,7 @@ #include "nsIDocumentStateListener.h" #include "nsIStyleContext.h" +#include "TypeInState.h" #include "nsIEnumerator.h" #include "nsIContent.h" @@ -482,7 +484,7 @@ nsresult nsHTMLEditor::SplitStyleAbovePoint(nsCOMPtr<nsIDOMNode> *aNode, // split any matching style nodes above the node/offset nsCOMPtr<nsIDOMNode> parent, tmp = *aNode; PRInt32 offset; - while (tmp && !nsHTMLEditUtils::IsBody(tmp)) + while (tmp && !nsTextEditUtils::IsBody(tmp)) { if ( (aProperty && NodeIsType(tmp, aProperty)) || // node is the correct inline prop (aProperty == nsIEditProperty::href && nsHTMLEditUtils::IsLink(tmp)) || // node is href - test if really <a href=... @@ -505,7 +507,9 @@ PRBool nsHTMLEditor::NodeIsProperty(nsIDOMNode *aNode) if (!aNode) return PR_FALSE; if (!IsContainer(aNode)) return PR_FALSE; if (!IsEditable(aNode)) return PR_FALSE; - if (!IsInlineNode(aNode)) return PR_FALSE; + PRBool isBlock (PR_FALSE); + NodeIsBlock(aNode, isBlock); + if (isBlock) return PR_FALSE; if (NodeIsType(aNode, nsIEditProperty::a)) return PR_FALSE; return PR_TRUE; } @@ -718,7 +722,7 @@ nsresult nsHTMLEditor::PromoteInlineRange(nsIDOMRange *inRange) if (NS_FAILED(res)) return res; while ( startNode && - !nsHTMLEditUtils::IsBody(startNode) && + !nsTextEditUtils::IsBody(startNode) && IsAtFrontOfNode(startNode, startOffset) ) { res = GetNodeLocation(startNode, address_of(parent), &startOffset); @@ -728,7 +732,7 @@ nsresult nsHTMLEditor::PromoteInlineRange(nsIDOMRange *inRange) if (!startNode) return NS_ERROR_NULL_POINTER; while ( endNode && - !nsHTMLEditUtils::IsBody(endNode) && + !nsTextEditUtils::IsBody(endNode) && IsAtEndOfNode(endNode, endOffset) ) { res = GetNodeLocation(endNode, address_of(parent), &endOffset); diff --git a/mozilla/editor/base/nsPlaintextDataTransfer.cpp b/mozilla/editor/base/nsPlaintextDataTransfer.cpp index 9c2a42f9fb3..227887e6e9b 100644 --- a/mozilla/editor/base/nsPlaintextDataTransfer.cpp +++ b/mozilla/editor/base/nsPlaintextDataTransfer.cpp @@ -22,9 +22,7 @@ #include "nsPlaintextEditor.h" -#include "nsHTMLEditUtils.h" - -#include "nsEditorEventListeners.h" +#include "nsTextEditUtils.h" #include "nsIDOMText.h" #include "nsIDOMNodeList.h" @@ -45,7 +43,6 @@ #include "nsIFrameSelection.h" // For TABLESELECTION_ defines #include "nsIIndependentSelection.h" //domselections answer to frameselection - #include "nsICSSLoader.h" #include "nsICSSStyleSheet.h" #include "nsIHTMLContentContainer.h" @@ -80,7 +77,6 @@ #include "nsAOLCiter.h" #include "nsInternetCiter.h" #include "nsISupportsPrimitives.h" -#include "InsertTextTxn.h" // netwerk #include "nsIURI.h" @@ -93,12 +89,7 @@ #include "nsIDragService.h" #include "nsIDOMNSUIEvent.h" -// Transactionas -#include "PlaceholderTxn.h" -#include "nsStyleSheetTxns.h" - // Misc -#include "TextEditorTest.h" #include "nsEditorUtils.h" #include "nsIPref.h" const PRUnichar nbsp = 160; diff --git a/mozilla/editor/base/nsPlaintextEditor.cpp b/mozilla/editor/base/nsPlaintextEditor.cpp index 73429bceb1f..507487a7e7f 100644 --- a/mozilla/editor/base/nsPlaintextEditor.cpp +++ b/mozilla/editor/base/nsPlaintextEditor.cpp @@ -22,7 +22,7 @@ #include "nsPlaintextEditor.h" #include "nsICaret.h" -#include "nsHTMLEditUtils.h" +#include "nsTextEditUtils.h" #include "nsTextEditRules.h" #include "nsEditorEventListeners.h" #include "nsIEditActionListener.h" @@ -70,22 +70,27 @@ #include "nsParserCIID.h" #include "nsIImage.h" #include "nsISupportsPrimitives.h" -#include "InsertTextTxn.h" // netwerk #include "nsIURI.h" #include "nsNetUtil.h" -// Transactionas -#include "PlaceholderTxn.h" - // Misc -#include "TextEditorTest.h" #include "nsEditorUtils.h" #include "nsIPref.h" #include "nsStyleConsts.h" #include "nsIStyleContext.h" +#include "nsAOLCiter.h" +#include "nsInternetCiter.h" + +// Drag & Drop, Clipboard +//#include "nsWidgetsCID.h" +#include "nsIClipboard.h" +#include "nsITransferable.h" +//#include "nsIDragService.h" +//#include "nsIDOMNSUIEvent.h" + const PRUnichar nbsp = 160; // HACK - CID for NS_CTRANSITIONAL_DTD_CID so that we can get at transitional dtd @@ -103,6 +108,11 @@ static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID); static NS_DEFINE_IID(kCParserIID, NS_IPARSER_IID); static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID); static NS_DEFINE_CID(kCTransitionalDTDCID, NS_CTRANSITIONAL_DTD_CID); +// Drag & Drop, Clipboard Support +static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); +static NS_DEFINE_CID(kCTransferableCID, NS_TRANSFERABLE_CID); +//static NS_DEFINE_CID(kCDragServiceCID, NS_DRAGSERVICE_CID); +//static NS_DEFINE_CID(kCHTMLFormatConverterCID, NS_HTMLFORMATCONVERTER_CID); #if defined(NS_DEBUG) && defined(DEBUG_buster) static PRBool gNoisy = PR_FALSE; @@ -110,10 +120,6 @@ static PRBool gNoisy = PR_FALSE; static const PRBool gNoisy = PR_FALSE; #endif -nsIAtom *nsPlaintextEditor::gTypingTxnName; -nsIAtom *nsPlaintextEditor::gIMETxnName; -nsIAtom *nsPlaintextEditor::gDeleteTxnName; - // prototype for rules creation shortcut nsresult NS_NewTextEditRules(nsIEditRules** aInstancePtrResult); @@ -127,57 +133,10 @@ nsPlaintextEditor::nsPlaintextEditor() { // Done in nsEditor // NS_INIT_REFCNT(); - if (!gTypingTxnName) - gTypingTxnName = NS_NewAtom("Typing"); - else - NS_ADDREF(gTypingTxnName); - if (!gIMETxnName) - gIMETxnName = NS_NewAtom("IME"); - else - NS_ADDREF(gIMETxnName); - if (!gDeleteTxnName) - gDeleteTxnName = NS_NewAtom("Deleting"); - else - NS_ADDREF(gDeleteTxnName); } nsPlaintextEditor::~nsPlaintextEditor() { - /* first, delete the transaction manager if there is one. - this will release any remaining transactions. - this is important because transactions can hold onto the atoms (gTypingTxnName, ...) - and to make the optimization (holding refcounted statics) work correctly, - the editor instance needs to hold the last refcount. - If you get this wrong, expect to deref a garbage gTypingTxnName pointer if you bring up a second editor. - */ - if (mTxnMgr) { - mTxnMgr = 0; - } - nsrefcnt refCount=0; - if (gTypingTxnName) // we addref'd in the constructor - { // want to release it without nulling out the pointer. - refCount = gTypingTxnName->Release(); - if (0==refCount) { - gTypingTxnName = nsnull; - } - } - - if (gIMETxnName) // we addref'd in the constructor - { // want to release it without nulling out the pointer. - refCount = gIMETxnName->Release(); - if (0==refCount) { - gIMETxnName = nsnull; - } - } - - if (gDeleteTxnName) // we addref'd in the constructor - { // want to release it without nulling out the pointer. - refCount = gDeleteTxnName->Release(); - if (0==refCount) { - gDeleteTxnName = nsnull; - } - } - // remove the rules as an action listener. Else we get a bad ownership loop later on. // it's ok if the rules aren't a listener; we ignore the error. nsCOMPtr<nsIEditActionListener> mListener = do_QueryInterface(mRules); @@ -227,6 +186,16 @@ NS_IMETHODIMP nsPlaintextEditor::QueryInterface(REFNSIID aIID, void** aInstanceP NS_ADDREF_THIS(); return NS_OK; } + if (aIID.Equals(NS_GET_IID(nsIEditor))) { + *aInstancePtr = NS_STATIC_CAST(nsIEditor*, this); + NS_ADDREF_THIS(); + return NS_OK; + } + if (aIID.Equals(NS_GET_IID(nsIEditorMailSupport))) { + *aInstancePtr = NS_STATIC_CAST(nsIEditorMailSupport*, this); + NS_ADDREF_THIS(); + return NS_OK; + } return nsEditor::QueryInterface(aIID, aInstancePtr); } @@ -1436,9 +1405,9 @@ NS_IMETHODIMP nsPlaintextEditor::CanCopy(PRBool &aCanCopy) // Shared between OutputToString and OutputToStream NS_IMETHODIMP nsPlaintextEditor::GetAndInitDocEncoder(const nsAReadableString& aFormatType, - PRUint32 aFlags, - const nsAReadableString* aCharset, - nsIDocumentEncoder** encoder) + PRUint32 aFlags, + const nsAReadableString* aCharset, + nsIDocumentEncoder** encoder) { nsCOMPtr<nsIPresShell> presShell; nsresult rv = GetPresShell(getter_AddRefs(presShell)); @@ -1484,7 +1453,7 @@ nsPlaintextEditor::GetAndInitDocEncoder(const nsAReadableString& aFormatType, nsCOMPtr<nsIDOMElement> rootElement; GetRootElement(getter_AddRefs(rootElement)); NS_ENSURE_TRUE(rootElement, NS_ERROR_FAILURE); - if (!nsHTMLEditUtils::IsBody(rootElement)) + if (!nsTextEditUtils::IsBody(rootElement)) { // XXX Why does this use range rather than selection collapse/extend? nsCOMPtr<nsIDOMRange> range (do_CreateInstance(kCRangeCID, &rv)); @@ -1582,6 +1551,297 @@ nsPlaintextEditor::OutputToStream(nsIOutputStream* aOutputStream, } +#ifdef XP_MAC +#pragma mark - +#pragma mark nsIEditorMailSupport overrides +#pragma mark - +#endif + +NS_IMETHODIMP +nsPlaintextEditor::PasteAsQuotation(PRInt32 aSelectionType) +{ + // Get Clipboard Service + nsresult rv; + NS_WITH_SERVICE(nsIClipboard, clipboard, kCClipboardCID, &rv); + if (NS_FAILED(rv)) return rv; + + // Create generic Transferable for getting the data + nsCOMPtr<nsITransferable> trans; + rv = nsComponentManager::CreateInstance(kCTransferableCID, nsnull, + NS_GET_IID(nsITransferable), + (void**) getter_AddRefs(trans)); + if (NS_SUCCEEDED(rv) && trans) + { + // We only handle plaintext pastes here + trans->AddDataFlavor(kUnicodeMime); + + // Get the Data from the clipboard + clipboard->GetData(trans, aSelectionType); + + // Now we ask the transferable for the data + // it still owns the data, we just have a pointer to it. + // If it can't support a "text" output of the data the call will fail + nsCOMPtr<nsISupports> genericDataObj; + PRUint32 len = 0; + char* flav = 0; + rv = trans->GetAnyTransferData(&flav, getter_AddRefs(genericDataObj), + &len); + if (NS_FAILED(rv)) + { +#ifdef DEBUG_akkana + printf("PasteAsPlaintextQuotation: GetAnyTransferData failed, %d\n", rv); +#endif + return rv; + } +#ifdef DEBUG_clipboard + printf("Got flavor [%s]\n", flav); +#endif + nsAutoString flavor; flavor.AssignWithConversion(flav); + nsAutoString stuffToPaste; + if (flavor.EqualsWithConversion(kUnicodeMime)) + { + nsCOMPtr<nsISupportsWString> textDataObj ( do_QueryInterface(genericDataObj) ); + if (textDataObj && len > 0) + { + PRUnichar* text = nsnull; + textDataObj->ToString ( &text ); + stuffToPaste.Assign ( text, len / 2 ); + nsAutoEditBatch beginBatching(this); + rv = InsertAsQuotation(stuffToPaste, 0); + if (text) + nsMemory::Free(text); + } + } + nsCRT::free(flav); + } + + return rv; +} + +// Utility routine to make a new citer. This addrefs, of course. +static nsICiter* MakeACiter() +{ + // Make a citer of an appropriate type + nsICiter* citer = 0; + nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &rv); + if (NS_FAILED(rv)) return 0; + + char *citationType = 0; + rv = prefs->CopyCharPref("mail.compose.citationType", &citationType); + + if (NS_SUCCEEDED(rv) && citationType[0]) + { + if (!strncmp(citationType, "aol", 3)) + citer = new nsAOLCiter; + else + citer = new nsInternetCiter; + PL_strfree(citationType); + } + else + citer = new nsInternetCiter; + + if (citer) + NS_ADDREF(citer); + return citer; +} + +NS_IMETHODIMP +nsPlaintextEditor::InsertAsQuotation(const nsString& aQuotedText, + nsIDOMNode **aNodeInserted) +{ + // We have the text. Cite it appropriately: + nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter()); + + // Let the citer quote it for us: + nsString quotedStuff; + nsresult rv = citer->GetCiteString(aQuotedText, quotedStuff); + if (!NS_SUCCEEDED(rv)) + return rv; + + // It's best to put a blank line after the quoted text so that mails + // written without thinking won't be so ugly. + quotedStuff.Append(PRUnichar('\n')); + + nsCOMPtr<nsIDOMNode> preNode; + // get selection + nsCOMPtr<nsISelection> selection; + rv = GetSelection(getter_AddRefs(selection)); + if (NS_FAILED(rv)) return rv; + if (!selection) return NS_ERROR_NULL_POINTER; + + nsAutoEditBatch beginBatching(this); + nsAutoRules beginRulesSniffing(this, kOpInsertText, nsIEditor::eNext); + + // give rules a chance to handle or cancel + nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertElement); + PRBool cancel, handled; + rv = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled); + if (NS_FAILED(rv)) return rv; + if (cancel) return NS_OK; // rules canceled the operation + if (!handled) + { + rv = InsertText(quotedStuff.GetUnicode()); + + // XXX Should set *aNodeInserted to the first node inserted + if (aNodeInserted && NS_SUCCEEDED(rv)) + { + *aNodeInserted = 0; + //NS_IF_ADDREF(*aNodeInserted); + } + } + return rv; +} + +NS_IMETHODIMP +nsPlaintextEditor::PasteAsCitedQuotation(const nsString& aCitation, + PRInt32 aSelectionType) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPlaintextEditor::InsertAsCitedQuotation(const nsString& aQuotedText, + const nsString& aCitation, + PRBool aInsertHTML, + const nsString& aCharset, + nsIDOMNode **aNodeInserted) +{ + return InsertAsQuotation(aQuotedText, aNodeInserted); +} + +NS_IMETHODIMP +nsPlaintextEditor::Rewrap(PRBool aRespectNewlines) +{ + PRInt32 wrapCol; + nsresult rv = GetWrapWidth(&wrapCol); + if (NS_FAILED(rv)) + return NS_OK; +#ifdef DEBUG_akkana + printf("nsPlaintextEditor::Rewrap to %ld columns\n", (long)wrapCol); +#endif + + nsCOMPtr<nsISelection> selection; + rv = GetSelection(getter_AddRefs(selection)); + if (NS_FAILED(rv)) return rv; + + if (!selection) + return NS_ERROR_NOT_INITIALIZED; + PRBool isCollapsed; + rv = selection->GetIsCollapsed(&isCollapsed); + if (NS_FAILED(rv)) return rv; + + // Variables we'll need either way + nsAutoString format; format.AssignWithConversion("text/plain"); + nsAutoString current; + nsString wrapped; + + if (isCollapsed) // rewrap the whole document + { + rv = OutputToString(current, format, + nsIDocumentEncoder::OutputFormatted); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter()); + if (NS_FAILED(rv)) return rv; + if (!citer) return NS_ERROR_UNEXPECTED; + + rv = citer->Rewrap(current, wrapCol, 0, aRespectNewlines, wrapped); + if (NS_FAILED(rv)) return rv; + + rv = SelectAll(); + if (NS_FAILED(rv)) return rv; + + return InsertText(wrapped.GetUnicode()); + } + else // rewrap only the selection + { + rv = OutputToString(current, format, + nsIDocumentEncoder::OutputFormatted + | nsIDocumentEncoder::OutputSelectionOnly); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter()); + if (NS_FAILED(rv)) return rv; + if (!citer) return NS_ERROR_UNEXPECTED; + + PRUint32 firstLineOffset = 0; // XXX need to get this + rv = citer->Rewrap(current, wrapCol, firstLineOffset, aRespectNewlines, + wrapped); + if (NS_FAILED(rv)) return rv; + + return InsertText(wrapped.GetUnicode()); + } + return NS_OK; +} + +NS_IMETHODIMP +nsPlaintextEditor::StripCites() +{ +#ifdef DEBUG_akkana + printf("nsPlaintextEditor::StripCites()\n"); +#endif + + nsCOMPtr<nsISelection> selection; + nsresult rv = GetSelection(getter_AddRefs(selection)); + if (NS_FAILED(rv)) return rv; + + if (!selection) + return NS_ERROR_NOT_INITIALIZED; + PRBool isCollapsed; + rv = selection->GetIsCollapsed(&isCollapsed); + if (NS_FAILED(rv)) return rv; + + // Variables we'll need either way + nsAutoString format; format.AssignWithConversion("text/plain"); + nsAutoString current; + nsString stripped; + + if (isCollapsed) // rewrap the whole document + { + rv = OutputToString(current, format, + nsIDocumentEncoder::OutputFormatted); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter()); + if (NS_FAILED(rv)) return rv; + if (!citer) return NS_ERROR_UNEXPECTED; + + rv = citer->StripCites(current, stripped); + if (NS_FAILED(rv)) return rv; + + rv = SelectAll(); + if (NS_FAILED(rv)) return rv; + + return InsertText(stripped.GetUnicode()); + } + else // rewrap only the selection + { + rv = OutputToString(current, format, + nsIDocumentEncoder::OutputFormatted + | nsIDocumentEncoder::OutputSelectionOnly); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter()); + if (NS_FAILED(rv)) return rv; + if (!citer) return NS_ERROR_UNEXPECTED; + + rv = citer->StripCites(current, stripped); + if (NS_FAILED(rv)) return rv; + + return InsertText(stripped.GetUnicode()); + } + return NS_OK; +} + +NS_IMETHODIMP +nsPlaintextEditor::GetEmbeddedObjects(nsISupportsArray** aNodeList) +{ + *aNodeList = 0; + return NS_OK; +} + + #ifdef XP_MAC #pragma mark - #pragma mark nsIEditorIMESupport overrides diff --git a/mozilla/editor/base/nsPlaintextEditor.h b/mozilla/editor/base/nsPlaintextEditor.h index c2bc4435a22..bfe586880ec 100644 --- a/mozilla/editor/base/nsPlaintextEditor.h +++ b/mozilla/editor/base/nsPlaintextEditor.h @@ -26,12 +26,12 @@ #include "nsCOMPtr.h" #include "nsIPlaintextEditor.h" +#include "nsIEditorMailSupport.h" #include "nsEditor.h" #include "nsIDOMElement.h" #include "nsIDOMEventListener.h" -#include "TypeInState.h" #include "nsEditRules.h" class nsIDOMKeyEvent; @@ -44,7 +44,8 @@ class nsIDocumentEncoder; * Use to edit text document represented as a DOM tree. */ class nsPlaintextEditor : public nsEditor, - public nsIPlaintextEditor + public nsIPlaintextEditor, + public nsIEditorMailSupport { public: @@ -67,6 +68,21 @@ public: /* ------------ nsIPlaintextEditor methods -------------- */ NS_DECL_NSIPLAINTEXTEDITOR + /* ------------ nsIEditorMailSupport overrides -------------- */ + NS_IMETHOD PasteAsQuotation(PRInt32 aSelectionType); + NS_IMETHOD InsertAsQuotation(const nsString& aQuotedText, + nsIDOMNode** aNodeInserted); + NS_IMETHOD PasteAsCitedQuotation(const nsString& aCitation, + PRInt32 aSelectionType); + NS_IMETHOD InsertAsCitedQuotation(const nsString& aQuotedText, + const nsString& aCitation, + PRBool aInsertHTML, + const nsString& aCharset, + nsIDOMNode** aNodeInserted); + NS_IMETHOD Rewrap(PRBool aRespectNewlines); + NS_IMETHOD StripCites(); + NS_IMETHOD GetEmbeddedObjects(nsISupportsArray** aNodeList); + /* ------------ nsIEditorIMESupport overrides -------------- */ NS_IMETHOD SetCompositionString(const nsString& aCompositionString, nsIPrivateTextRangeList* aTextRangeList,nsTextEventReply* aReply); @@ -212,11 +228,6 @@ protected: PRInt32 mMaxTextLength; PRInt32 mInitTriggerCounter; -public: - static nsIAtom *gTypingTxnName; - static nsIAtom *gIMETxnName; - static nsIAtom *gDeleteTxnName; - // friends friend class nsHTMLEditRules; friend class nsTextEditRules; diff --git a/mozilla/editor/base/nsTableEditor.cpp b/mozilla/editor/base/nsTableEditor.cpp index 694e88e3f66..426d1bfe361 100644 --- a/mozilla/editor/base/nsTableEditor.cpp +++ b/mozilla/editor/base/nsTableEditor.cpp @@ -45,6 +45,7 @@ #include "nsVoidArray.h" #include "nsEditorUtils.h" +#include "nsTextEditUtils.h" #include "nsHTMLEditUtils.h" static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID); @@ -3534,7 +3535,7 @@ nsHTMLEditor::IsEmptyCell(nsIDOMElement *aCell) { // We insert a single break into a cell by default // to have some place to locate a cursor -- it is dispensable - PRBool isEmpty = nsHTMLEditUtils::IsBreak(cellChild); + PRBool isEmpty = nsTextEditUtils::IsBreak(cellChild); // Or check if no real content if (!isEmpty) IsEmptyNode(cellChild, &isEmpty, PR_FALSE, PR_FALSE); diff --git a/mozilla/editor/base/nsTextEditRules.cpp b/mozilla/editor/base/nsTextEditRules.cpp index cf864354653..62b116eb4c3 100644 --- a/mozilla/editor/base/nsTextEditRules.cpp +++ b/mozilla/editor/base/nsTextEditRules.cpp @@ -23,7 +23,7 @@ #include "nsTextEditRules.h" #include "nsEditor.h" -#include "nsHTMLEditUtils.h" +#include "nsTextEditUtils.h" #include "nsCOMPtr.h" #include "nsIDOMNode.h" @@ -37,10 +37,8 @@ #include "nsIContentIterator.h" #include "nsIEnumerator.h" #include "nsLayoutCID.h" -#include "nsIEditProperty.h" #include "nsEditorUtils.h" #include "EditTxn.h" -#include "TypeInState.h" #include "nsIPref.h" #ifdef IBMBIDI #include "nsIPresContext.h" @@ -165,8 +163,6 @@ nsTextEditRules::SetFlags(PRUint32 aFlags) // SetFlags() is really meant to only be called once // and at editor init time. - PRBool willBePlaintext = (aFlags & nsIPlaintextEditor::eEditorPlaintextMask) != 0; - PRBool alreadyPlaintext = (mFlags & nsIPlaintextEditor::eEditorPlaintextMask) != 0; mFlags = aFlags; return NS_OK; } @@ -422,7 +418,7 @@ nsTextEditRules::DidInsertBreak(nsISelection *aSelection, nsresult aResult) temp = mEditor->GetChildAt(selNode, selOffset); if (temp) return NS_OK; // cant be at end of there is a node after us. nearNode = mEditor->GetChildAt(selNode, selOffset-1); - if (nearNode && nsHTMLEditUtils::IsBreak(nearNode) && !nsHTMLEditUtils::IsMozBR(nearNode)) + if (nearNode && nsTextEditUtils::IsBreak(nearNode) && !nsTextEditUtils::IsMozBR(nearNode)) { nsCOMPtr<nsISelection> sel(aSelection); nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(sel)); diff --git a/mozilla/editor/composer/src/nsEditorShell.cpp b/mozilla/editor/composer/src/nsEditorShell.cpp index b1b21fa5d95..11e29960ef6 100644 --- a/mozilla/editor/composer/src/nsEditorShell.cpp +++ b/mozilla/editor/composer/src/nsEditorShell.cpp @@ -83,7 +83,7 @@ #include "nsICommonDialogs.h" #include "nsIEditorController.h" -#include "nsEditorController.h" +//#include "nsEditorController.h" #include "nsIControllers.h" #include "nsIDocShell.h" #include "nsIDocShellTreeItem.h" @@ -124,8 +124,6 @@ #include "nsISpellChecker.h" #include "nsInterfaceState.h" -#include "nsAOLCiter.h" -#include "nsInternetCiter.h" #include "nsEditorShellMouseListener.h" /////////////////////////////////////// @@ -2285,9 +2283,7 @@ nsEditorShell::NodeIsBlock(nsIDOMNode *node, PRBool *_retval) case ePlainTextEditorType: case eHTMLTextEditorType: { - nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor); - if (editor) - rv = editor->NodeIsBlock(node, *_retval); + rv = mEditor->NodeIsBlock(node, *_retval); } break; @@ -2534,174 +2530,22 @@ nsEditorShell::InsertAsCitedQuotation(const PRUnichar *quotedText, return err; } -// Utility routine to make a new citer. This addrefs, of course. -static nsICiter* MakeACiter() -{ - // Make a citer of an appropriate type - nsICiter* citer = 0; - nsresult rv; - NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &rv); - if (NS_FAILED(rv)) return 0; - - char *citationType = 0; - rv = prefs->CopyCharPref("mail.compose.citationType", &citationType); - - if (NS_SUCCEEDED(rv) && citationType[0]) - { - if (!strncmp(citationType, "aol", 3)) - citer = new nsAOLCiter; - else - citer = new nsInternetCiter; - PL_strfree(citationType); - } - else - citer = new nsInternetCiter; - - if (citer) - NS_ADDREF(citer); - return citer; -} - NS_IMETHODIMP nsEditorShell::Rewrap(PRBool aRespectNewlines) { - PRInt32 wrapCol; - nsresult rv = GetWrapColumn(&wrapCol); - if (NS_FAILED(rv)) - return NS_OK; -#ifdef DEBUG_akkana - printf("nsEditorShell::Rewrap to %ld columns\n", (long)wrapCol); -#endif - - nsCOMPtr<nsISelection> selection; - rv = GetEditorSelection(getter_AddRefs(selection)); - if (NS_FAILED(rv)) return rv; - - if (!selection) - return NS_ERROR_NOT_INITIALIZED; - PRBool isCollapsed; - rv = selection->GetIsCollapsed(&isCollapsed); - if (NS_FAILED(rv)) return rv; - - // Variables we'll need either way - nsAutoString format; format.AssignWithConversion("text/plain"); - nsAutoString current; - nsString wrapped; - nsCOMPtr<nsIEditor> nsied (do_QueryInterface(mEditor)); - if (!nsied) - return NS_ERROR_UNEXPECTED; - - if (isCollapsed) // rewrap the whole document - { - rv = nsied->OutputToString(current, format, - nsIDocumentEncoder::OutputFormatted); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter()); - if (NS_FAILED(rv)) return rv; - if (!citer) return NS_ERROR_UNEXPECTED; - - rv = citer->Rewrap(current, wrapCol, 0, aRespectNewlines, wrapped); - if (NS_FAILED(rv)) return rv; - - rv = SelectAll(); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr<nsIPlaintextEditor> textEditor (do_QueryInterface(mEditor)); - if (!textEditor) - return NS_NOINTERFACE; - return textEditor->InsertText(wrapped.GetUnicode()); - } - else // rewrap only the selection - { - rv = nsied->OutputToString(current, format, - nsIDocumentEncoder::OutputFormatted - | nsIDocumentEncoder::OutputSelectionOnly); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter()); - if (NS_FAILED(rv)) return rv; - if (!citer) return NS_ERROR_UNEXPECTED; - - PRUint32 firstLineOffset = 0; // XXX need to get this - rv = citer->Rewrap(current, wrapCol, firstLineOffset, aRespectNewlines, - wrapped); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr<nsIPlaintextEditor> textEditor (do_QueryInterface(mEditor)); - if (!textEditor) - return NS_NOINTERFACE; - return textEditor->InsertText(wrapped.GetUnicode()); - } - return NS_OK; + nsCOMPtr<nsIEditorMailSupport> mailEditor = do_QueryInterface(mEditor); + if (!mailEditor) + return NS_NOINTERFACE; + return mailEditor->Rewrap(aRespectNewlines); } NS_IMETHODIMP nsEditorShell::StripCites() { -#ifdef DEBUG_akkana - printf("nsEditorShell::StripCites()\n"); -#endif - - nsCOMPtr<nsISelection> selection; - nsresult rv = GetEditorSelection(getter_AddRefs(selection)); - if (NS_FAILED(rv)) return rv; - - if (!selection) - return NS_ERROR_NOT_INITIALIZED; - PRBool isCollapsed; - rv = selection->GetIsCollapsed(&isCollapsed); - if (NS_FAILED(rv)) return rv; - - // Variables we'll need either way - nsAutoString format; format.AssignWithConversion("text/plain"); - nsAutoString current; - nsString stripped; - nsCOMPtr<nsIEditor> nsied (do_QueryInterface(mEditor)); - if (!nsied) - return NS_ERROR_UNEXPECTED; - - if (isCollapsed) // rewrap the whole document - { - rv = nsied->OutputToString(current, format, - nsIDocumentEncoder::OutputFormatted); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter()); - if (NS_FAILED(rv)) return rv; - if (!citer) return NS_ERROR_UNEXPECTED; - - rv = citer->StripCites(current, stripped); - if (NS_FAILED(rv)) return rv; - - rv = SelectAll(); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr<nsIPlaintextEditor> textEditor (do_QueryInterface(mEditor)); - if (!textEditor) - return NS_NOINTERFACE; - return textEditor->InsertText(stripped.GetUnicode()); - } - else // rewrap only the selection - { - rv = nsied->OutputToString(current, format, - nsIDocumentEncoder::OutputFormatted - | nsIDocumentEncoder::OutputSelectionOnly); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter()); - if (NS_FAILED(rv)) return rv; - if (!citer) return NS_ERROR_UNEXPECTED; - - rv = citer->StripCites(current, stripped); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr<nsIPlaintextEditor> textEditor (do_QueryInterface(mEditor)); - if (!textEditor) - return NS_NOINTERFACE; - return textEditor->InsertText(stripped.GetUnicode()); - } - return NS_OK; + nsCOMPtr<nsIEditorMailSupport> mailEditor = do_QueryInterface(mEditor); + if (!mailEditor) + return NS_NOINTERFACE; + return mailEditor->StripCites(); } NS_IMETHODIMP diff --git a/mozilla/editor/composer/src/nsEditorShellMouseListener.cpp b/mozilla/editor/composer/src/nsEditorShellMouseListener.cpp index ae4a9066bb5..ea5b2c528a7 100644 --- a/mozilla/editor/composer/src/nsEditorShellMouseListener.cpp +++ b/mozilla/editor/composer/src/nsEditorShellMouseListener.cpp @@ -40,7 +40,6 @@ #include "nsIEditor.h" #include "nsIHTMLEditor.h" -#include "nsHTMLEditUtils.h" /* * nsEditorShellMouseListener implementation @@ -270,17 +269,19 @@ nsEditorShellMouseListener::MouseDown(nsIDOMEvent* aMouseEvent) } } +#ifdef CMANSKE_PLEASE_FIX_THIS if (isContextClick) { // Set selection to node clicked on if NOT within an existing selection // and not the entire body or table element if (element && !NodeIsInSelection && - !nsHTMLEditUtils::IsBody(element) && + !nsTextEditUtils::IsBody(element) && !nsHTMLEditUtils::IsTableElement(element)) { mEditorShell->SelectElement(element); } } +#endif /* CMANSKE_PLEASE_FIX_THIS */ else if (buttonNumber == 0) { if (tableMode && clickCount == 2) diff --git a/mozilla/editor/libeditor/base/PlaceholderTxn.cpp b/mozilla/editor/libeditor/base/PlaceholderTxn.cpp index 68fae46d9e0..af7cee71848 100644 --- a/mozilla/editor/libeditor/base/PlaceholderTxn.cpp +++ b/mozilla/editor/libeditor/base/PlaceholderTxn.cpp @@ -23,7 +23,7 @@ #include "PlaceholderTxn.h" #include "nsVoidArray.h" -#include "nsHTMLEditor.h" +#include "nsEditor.h" #include "nsIPresShell.h" #include "IMETextTxn.h" @@ -178,9 +178,9 @@ NS_IMETHODIMP PlaceholderTxn::Merge(nsITransaction *aTransaction, PRBool *aDidMe } else { // merge typing or IME or deletion transactions if the selection matches - if (((mName.get() == nsHTMLEditor::gTypingTxnName) || - (mName.get() == nsHTMLEditor::gIMETxnName) || - (mName.get() == nsHTMLEditor::gDeleteTxnName)) + if (((mName.get() == nsEditor::gTypingTxnName) || + (mName.get() == nsEditor::gIMETxnName) || + (mName.get() == nsEditor::gDeleteTxnName)) && !mCommitted ) { // but only if this placeholder started with a collapsed selection diff --git a/mozilla/editor/libeditor/base/SetDocTitleTxn.cpp b/mozilla/editor/libeditor/base/SetDocTitleTxn.cpp index aa879c9651c..9d367d348a4 100644 --- a/mozilla/editor/libeditor/base/SetDocTitleTxn.cpp +++ b/mozilla/editor/libeditor/base/SetDocTitleTxn.cpp @@ -23,7 +23,6 @@ #include "SetDocTitleTxn.h" #include "nsEditor.h" -#include "nsHTMLEditor.h" #include "nsIDOMNode.h" #include "nsIDOMNodeList.h" #include "nsIDOMDocument.h" @@ -81,7 +80,8 @@ nsresult SetDocTitleTxn::SetDocTitle(nsString& aTitle) nsCOMPtr<nsIDOMDocument> domDoc; nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor); if (!editor) return NS_ERROR_FAILURE; - nsresult res = editor->GetDocument(getter_AddRefs(domDoc)); + nsresult rv = editor->GetDocument(getter_AddRefs(domDoc)); + if (NS_FAILED(rv)) return rv; if (!domDoc) return NS_ERROR_FAILURE; nsCOMPtr<nsIDOMHTMLDocument> HTMLDoc = do_QueryInterface(domDoc); if (!HTMLDoc) return NS_ERROR_FAILURE; diff --git a/mozilla/editor/libeditor/base/nsEditor.cpp b/mozilla/editor/libeditor/base/nsEditor.cpp index 51d6541f0a7..80020203c3f 100644 --- a/mozilla/editor/libeditor/base/nsEditor.cpp +++ b/mozilla/editor/libeditor/base/nsEditor.cpp @@ -28,7 +28,6 @@ #include "nsIDOMDocument.h" #include "nsIPref.h" #include "nsILocale.h" -#include "nsIEditProperty.h" // to be removed XXX #include "nsIDOMText.h" #include "nsIDOMElement.h" @@ -145,7 +144,6 @@ static const PRBool gNoisy = PR_FALSE; #endif -const PRUnichar nbsp = 160; PRInt32 nsEditor::gInstanceCount = 0; @@ -155,6 +153,9 @@ PRInt32 nsEditor::gInstanceCount = 0; // //--------------------------------------------------------------------------- +nsIAtom *nsEditor::gTypingTxnName; +nsIAtom *nsEditor::gIMETxnName; +nsIAtom *nsEditor::gDeleteTxnName; nsEditor::nsEditor() : mPresShellWeak(nsnull) @@ -184,10 +185,58 @@ nsEditor::nsEditor() NS_INIT_REFCNT(); PR_AtomicIncrement(&gInstanceCount); + + if (!gTypingTxnName) + gTypingTxnName = NS_NewAtom("Typing"); + else + NS_ADDREF(gTypingTxnName); + if (!gIMETxnName) + gIMETxnName = NS_NewAtom("IME"); + else + NS_ADDREF(gIMETxnName); + if (!gDeleteTxnName) + gDeleteTxnName = NS_NewAtom("Deleting"); + else + NS_ADDREF(gDeleteTxnName); } nsEditor::~nsEditor() { + /* first, delete the transaction manager if there is one. + this will release any remaining transactions. + this is important because transactions can hold onto the atoms (gTypingTxnName, ...) + and to make the optimization (holding refcounted statics) work correctly, + the editor instance needs to hold the last refcount. + If you get this wrong, expect to deref a garbage gTypingTxnName pointer if you bring up a second editor. + */ + if (mTxnMgr) { + mTxnMgr = 0; + } + nsrefcnt refCount=0; + if (gTypingTxnName) // we addref'd in the constructor + { // want to release it without nulling out the pointer. + refCount = gTypingTxnName->Release(); + if (0==refCount) { + gTypingTxnName = nsnull; + } + } + + if (gIMETxnName) // we addref'd in the constructor + { // want to release it without nulling out the pointer. + refCount = gIMETxnName->Release(); + if (0==refCount) { + gIMETxnName = nsnull; + } + } + + if (gDeleteTxnName) // we addref'd in the constructor + { // want to release it without nulling out the pointer. + refCount = gDeleteTxnName->Release(); + if (0==refCount) { + gDeleteTxnName = nsnull; + } + } + delete mEditorObservers; // no need to release observers; we didn't addref them mEditorObservers = 0; @@ -252,11 +301,6 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIPresShell* aPresShell, nsIContent *aRoot // is no way to do that right now. So we leave it null here and set // up a nav html dtd in nsHTMLEditor::Init - // Init mEditProperty - nsresult result = NS_NewEditProperty(getter_AddRefs(mEditProperty)); - if (NS_FAILED(result)) { return result; } - if (!mEditProperty) {return NS_ERROR_NULL_POINTER;} - ps->GetViewManager(&mViewManager); if (!mViewManager) {return NS_ERROR_NULL_POINTER;} mViewManager->Release(); //we want a weak link @@ -3033,102 +3077,6 @@ nsEditor::GetLengthOfDOMNode(nsIDOMNode *aNode, PRUint32 &aCount) return result; } -// Non-static version for the nsIEditor interface and JavaScript -NS_IMETHODIMP -nsEditor::NodeIsBlock(nsIDOMNode *aNode, PRBool &aIsBlock) -{ - if (!aNode) { return NS_ERROR_NULL_POINTER; } - return IsNodeBlock(aNode, aIsBlock); -} - -// The list of block nodes is shorter, so do the real work here... -nsresult -nsEditor::IsNodeBlock(nsIDOMNode *aNode, PRBool &aIsBlock) -{ - // this is a content-based implementation - if (!aNode) { return NS_ERROR_NULL_POINTER; } - - nsresult result = NS_ERROR_FAILURE; - aIsBlock = PR_FALSE; - nsCOMPtr<nsIDOMElement>element; - element = do_QueryInterface(aNode); - if (element) - { - nsAutoString tagName; - result = element->GetTagName(tagName); - if (NS_SUCCEEDED(result)) - { - tagName.ToLowerCase(); - nsIAtom *tagAtom = NS_NewAtom(tagName); - if (!tagAtom) { return NS_ERROR_NULL_POINTER; } - - if (tagAtom==nsIEditProperty::p || - tagAtom==nsIEditProperty::div || - tagAtom==nsIEditProperty::blockquote || - tagAtom==nsIEditProperty::h1 || - tagAtom==nsIEditProperty::h2 || - tagAtom==nsIEditProperty::h3 || - tagAtom==nsIEditProperty::h4 || - tagAtom==nsIEditProperty::h5 || - tagAtom==nsIEditProperty::h6 || - tagAtom==nsIEditProperty::ul || - tagAtom==nsIEditProperty::ol || - tagAtom==nsIEditProperty::dl || - tagAtom==nsIEditProperty::pre || - tagAtom==nsIEditProperty::noscript || - tagAtom==nsIEditProperty::form || - tagAtom==nsIEditProperty::hr || - tagAtom==nsIEditProperty::table || - tagAtom==nsIEditProperty::fieldset || - tagAtom==nsIEditProperty::address || - tagAtom==nsIEditProperty::body || - tagAtom==nsIEditProperty::tr || - tagAtom==nsIEditProperty::td || - tagAtom==nsIEditProperty::th || - tagAtom==nsIEditProperty::caption || - tagAtom==nsIEditProperty::col || - tagAtom==nsIEditProperty::colgroup || - tagAtom==nsIEditProperty::tbody || - tagAtom==nsIEditProperty::thead || - tagAtom==nsIEditProperty::tfoot || - tagAtom==nsIEditProperty::li || - tagAtom==nsIEditProperty::dt || - tagAtom==nsIEditProperty::dd || - tagAtom==nsIEditProperty::legend ) - { - aIsBlock = PR_TRUE; - } - NS_RELEASE(tagAtom); - result = NS_OK; - } - } else { - // We don't have an element -- probably a text node - nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(aNode); - if (nodeAsText) - { - aIsBlock = PR_FALSE; - result = NS_OK; - } - } - return result; -} - -// ...and simply assume non-block element is inline -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; - PRBool IsBlock = PR_FALSE; - result = IsNodeBlock(aNode, IsBlock); - aIsInline = !IsBlock; - return result; -} - - nsresult nsEditor::GetPriorNode(nsIDOMNode *aParentNode, PRInt32 aOffset, @@ -3892,238 +3840,6 @@ nsEditor::NodesSameType(nsIDOMNode *aNode1, nsIDOMNode *aNode2) } - -/////////////////////////////////////////////////////////////////////////// -// IsBlockNode: true if this node is an html block node -// -PRBool -nsEditor::IsBlockNode(nsIDOMNode *aNode) -{ - return !IsInlineNode(aNode); -} - - -/////////////////////////////////////////////////////////////////////////// -// IsInlineNode: true if this node is an html inline node -// -PRBool -nsEditor::IsInlineNode(nsIDOMNode *aNode) -{ - PRBool retVal = PR_FALSE; - IsNodeInline(aNode, retVal); - return retVal; -} - - -/////////////////////////////////////////////////////////////////////////// -// GetBlockNodeParent: returns enclosing block level ancestor, if any -// -nsCOMPtr<nsIDOMNode> -nsEditor::GetBlockNodeParent(nsIDOMNode *aNode) -{ - nsCOMPtr<nsIDOMNode> tmp; - nsCOMPtr<nsIDOMNode> p; - - if (!aNode) - { - NS_NOTREACHED("null node passed to GetBlockNodeParent()"); - return PR_FALSE; - } - - if (NS_FAILED(aNode->GetParentNode(getter_AddRefs(p)))) // no parent, ran off top of tree - return tmp; - - while (p && !IsBlockNode(p)) - { - if ( NS_FAILED(p->GetParentNode(getter_AddRefs(tmp))) || !tmp) // no parent, ran off top of tree - return p; - - p = tmp; - } - return p; -} - - -/////////////////////////////////////////////////////////////////////////// -// HasSameBlockNodeParent: true if nodes have same block level ancestor -// -PRBool -nsEditor::HasSameBlockNodeParent(nsIDOMNode *aNode1, nsIDOMNode *aNode2) -{ - if (!aNode1 || !aNode2) - { - NS_NOTREACHED("null node passed to HasSameBlockNodeParent()"); - return PR_FALSE; - } - - if (aNode1 == aNode2) - return PR_TRUE; - - nsCOMPtr<nsIDOMNode> p1 = GetBlockNodeParent(aNode1); - nsCOMPtr<nsIDOMNode> p2 = GetBlockNodeParent(aNode2); - - return (p1 == p2); -} - - -/////////////////////////////////////////////////////////////////////////// -// GetBlockSection: return leftmost/rightmost nodes in aChild's block -// -nsresult -nsEditor::GetBlockSection(nsIDOMNode *aChild, - nsIDOMNode **aLeftNode, - nsIDOMNode **aRightNode) -{ - nsresult result = NS_OK; - if (!aChild || !aLeftNode || !aRightNode) {return NS_ERROR_NULL_POINTER;} - *aLeftNode = aChild; - *aRightNode = aChild; - - nsCOMPtr<nsIDOMNode>sibling; - result = aChild->GetPreviousSibling(getter_AddRefs(sibling)); - while ((NS_SUCCEEDED(result)) && sibling) - { - PRBool isInline; - IsNodeInline(sibling, isInline); - if (PR_FALSE==isInline) - { - nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling); - if (!nodeAsText) { - break; - } - // XXX: needs some logic to work for other leaf nodes besides text! - } - *aLeftNode = sibling; - result = (*aLeftNode)->GetPreviousSibling(getter_AddRefs(sibling)); - } - NS_ADDREF((*aLeftNode)); - // now do the right side - result = aChild->GetNextSibling(getter_AddRefs(sibling)); - while ((NS_SUCCEEDED(result)) && sibling) - { - PRBool isInline; - IsNodeInline(sibling, isInline); - if (PR_FALSE==isInline) - { - nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling); - if (!nodeAsText) { - break; - } - } - *aRightNode = sibling; - result = (*aRightNode)->GetNextSibling(getter_AddRefs(sibling)); - } - NS_ADDREF((*aRightNode)); - if (gNoisy) { printf("GetBlockSection returning %p %p\n", - (void*)(*aLeftNode), (void*)(*aRightNode)); } - - return result; -} - - -/////////////////////////////////////////////////////////////////////////// -// GetBlockSectionsForRange: return list of block sections that intersect -// this range -nsresult -nsEditor::GetBlockSectionsForRange(nsIDOMRange *aRange, nsISupportsArray *aSections) -{ - if (!aRange || !aSections) {return NS_ERROR_NULL_POINTER;} - - nsresult result; - nsCOMPtr<nsIContentIterator>iter; - result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull, - NS_GET_IID(nsIContentIterator), getter_AddRefs(iter)); - if ((NS_SUCCEEDED(result)) && iter) - { - nsCOMPtr<nsIDOMRange> lastRange; - iter->Init(aRange); - nsCOMPtr<nsIContent> currentContent; - iter->CurrentNode(getter_AddRefs(currentContent)); - while (NS_ENUMERATOR_FALSE == iter->IsDone()) - { - nsCOMPtr<nsIDOMNode>currentNode = do_QueryInterface(currentContent); - if (currentNode) - { - nsCOMPtr<nsIAtom> currentContentTag; - currentContent->GetTag(*getter_AddRefs(currentContentTag)); - // <BR> divides block content ranges. We can achieve this by nulling out lastRange - if (nsIEditProperty::br==currentContentTag.get()) - { - lastRange = do_QueryInterface(nsnull); - } - else - { - PRBool isInlineOrText; - result = IsNodeInline(currentNode, isInlineOrText); - if (PR_FALSE==isInlineOrText) - { - PRUint16 nodeType; - currentNode->GetNodeType(&nodeType); - if (nsIDOMNode::TEXT_NODE == nodeType) { - isInlineOrText = PR_TRUE; - } - } - if (PR_TRUE==isInlineOrText) - { - nsCOMPtr<nsIDOMNode>leftNode; - nsCOMPtr<nsIDOMNode>rightNode; - result = GetBlockSection(currentNode, - getter_AddRefs(leftNode), - getter_AddRefs(rightNode)); - if (gNoisy) {printf("currentNode %p has block content (%p,%p)\n", (void*)currentNode.get(), (void*)leftNode.get(), (void*)rightNode.get());} - if ((NS_SUCCEEDED(result)) && leftNode && rightNode) - { - // add range to the list if it doesn't overlap with the previous range - PRBool addRange=PR_TRUE; - if (lastRange) - { - nsCOMPtr<nsIDOMNode> lastStartNode; - nsCOMPtr<nsIDOMElement> blockParentOfLastStartNode; - lastRange->GetStartContainer(getter_AddRefs(lastStartNode)); - blockParentOfLastStartNode = do_QueryInterface(GetBlockNodeParent(lastStartNode)); - if (blockParentOfLastStartNode) - { - if (gNoisy) {printf("lastStartNode %p has block parent %p\n", (void*)lastStartNode.get(), (void*)blockParentOfLastStartNode.get());} - nsCOMPtr<nsIDOMElement> blockParentOfLeftNode; - blockParentOfLeftNode = do_QueryInterface(GetBlockNodeParent(leftNode)); - if (blockParentOfLeftNode) - { - if (gNoisy) {printf("leftNode %p has block parent %p\n", (void*)leftNode.get(), (void*)blockParentOfLeftNode.get());} - if (blockParentOfLastStartNode==blockParentOfLeftNode) { - addRange = PR_FALSE; - } - } - } - } - if (PR_TRUE==addRange) - { - if (gNoisy) {printf("adding range, setting lastRange with start node %p\n", (void*)leftNode.get());} - nsCOMPtr<nsIDOMRange> range; - result = nsComponentManager::CreateInstance(kCRangeCID, nsnull, - NS_GET_IID(nsIDOMRange), 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; -} - - /////////////////////////////////////////////////////////////////////////// // IsTextOrElementNode: true if node of dom type element or text // @@ -4215,61 +3931,6 @@ nsEditor::GetChildAt(nsIDOMNode *aParent, PRInt32 aOffset) -/////////////////////////////////////////////////////////////////////////// -// NextNodeInBlock: gets the next/prev node in the block, if any. Next node -// must be an element or text node, others are ignored -nsCOMPtr<nsIDOMNode> -nsEditor::NextNodeInBlock(nsIDOMNode *aNode, IterDirection aDir) -{ - nsCOMPtr<nsIDOMNode> nullNode; - nsCOMPtr<nsIContent> content; - nsCOMPtr<nsIContent> blockContent; - nsCOMPtr<nsIDOMNode> node; - nsCOMPtr<nsIDOMNode> blockParent; - - if (!aNode) return nullNode; - - nsCOMPtr<nsIContentIterator> iter; - if (NS_FAILED(nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull, - NS_GET_IID(nsIContentIterator), - getter_AddRefs(iter)))) - return nullNode; - - // much gnashing of teeth as we twit back and forth between content and domnode types - content = do_QueryInterface(aNode); - if (IsBlockNode(aNode)) - { - blockParent = do_QueryInterface(aNode); - } - else - { - blockParent = GetBlockNodeParent(aNode); - } - if (!blockParent) return nullNode; - blockContent = do_QueryInterface(blockParent); - if (!blockContent) return nullNode; - - if (NS_FAILED(iter->Init(blockContent))) return nullNode; - if (NS_FAILED(iter->PositionAt(content))) return nullNode; - - while (NS_ENUMERATOR_FALSE == iter->IsDone()) - { - if (NS_FAILED(iter->CurrentNode(getter_AddRefs(content)))) return nullNode; - // ignore nodes that aren't elements or text, or that are the block parent - node = do_QueryInterface(content); - if (node && IsTextOrElementNode(node) && (node != blockParent) && (node.get() != aNode)) - return node; - - if (aDir == kIterForward) - iter->Next(); - else - iter->Prev(); - } - - return nullNode; -} - - /////////////////////////////////////////////////////////////////////////// // GetStartNodeAndOffset: returns whatever the start parent & offset is of // the first range in the selection. @@ -4387,148 +4048,6 @@ nsEditor::IsPreformatted(nsIDOMNode *aNode, PRBool *aResult) } -/////////////////////////////////////////////////////////////////////////// -// IsNextCharWhitespace: checks the adjacent content in the same block -// to see if following selection is whitespace or nbsp -nsresult -nsEditor::IsNextCharWhitespace(nsIDOMNode *aParentNode, - PRInt32 aOffset, - PRBool *outIsSpace, - PRBool *outIsNBSP, - nsCOMPtr<nsIDOMNode> *outNode, - PRInt32 *outOffset) -{ - if (!outIsSpace || !outIsNBSP) return NS_ERROR_NULL_POINTER; - *outIsSpace = PR_FALSE; - *outIsNBSP = PR_FALSE; - if (outNode) *outNode = nsnull; - if (outOffset) *outOffset = -1; - - nsAutoString tempString; - PRUint32 strLength; - nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(aParentNode); - if (textNode) - { - textNode->GetLength(&strLength); - if ((PRUint32)aOffset < strLength) - { - // easy case: next char is in same node - textNode->SubstringData(aOffset,aOffset+1,tempString); - *outIsSpace = nsCRT::IsAsciiSpace(tempString.First()); - *outIsNBSP = (tempString.First() == nbsp); - if (outNode) *outNode = do_QueryInterface(aParentNode); - if (outOffset) *outOffset = aOffset+1; // yes, this is _past_ the character; - return NS_OK; - } - } - - // harder case: next char in next node. - nsCOMPtr<nsIDOMNode> node = NextNodeInBlock(aParentNode, kIterForward); - nsCOMPtr<nsIDOMNode> tmp; - while (node) - { - if (!IsInlineNode(node)) // skip over bold, italic, link, ect nodes - { - if (IsTextNode(node) && IsEditable(node)) - { - textNode = do_QueryInterface(node); - textNode->GetLength(&strLength); - if (strLength) - { - textNode->SubstringData(0,1,tempString); - *outIsSpace = nsCRT::IsAsciiSpace(tempString.First()); - *outIsNBSP = (tempString.First() == nbsp); - if (outNode) *outNode = do_QueryInterface(node); - if (outOffset) *outOffset = 1; // yes, this is _past_ the character; - return NS_OK; - } - // else it's an empty text node, or not editable; skip it. - } - else // node is an image or some other thingy that doesn't count as whitespace - { - break; - } - } - tmp = node; - node = NextNodeInBlock(tmp, kIterForward); - } - - return NS_OK; -} - - -/////////////////////////////////////////////////////////////////////////// -// IsPrevCharWhitespace: checks the adjacent content in the same block -// to see if following selection is whitespace -nsresult -nsEditor::IsPrevCharWhitespace(nsIDOMNode *aParentNode, - PRInt32 aOffset, - PRBool *outIsSpace, - PRBool *outIsNBSP, - nsCOMPtr<nsIDOMNode> *outNode, - PRInt32 *outOffset) -{ - if (!outIsSpace || !outIsNBSP) return NS_ERROR_NULL_POINTER; - *outIsSpace = PR_FALSE; - *outIsNBSP = PR_FALSE; - if (outNode) *outNode = nsnull; - if (outOffset) *outOffset = -1; - - nsAutoString tempString; - PRUint32 strLength; - nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(aParentNode); - if (textNode) - { - if (aOffset > 0) - { - // easy case: prev char is in same node - textNode->SubstringData(aOffset-1,aOffset,tempString); - *outIsSpace = nsCRT::IsAsciiSpace(tempString.First()); - *outIsNBSP = (tempString.First() == nbsp); - if (outNode) *outNode = do_QueryInterface(aParentNode); - if (outOffset) *outOffset = aOffset-1; - return NS_OK; - } - } - - // harder case: prev char in next node - nsCOMPtr<nsIDOMNode> node = NextNodeInBlock(aParentNode, kIterBackward); - nsCOMPtr<nsIDOMNode> tmp; - while (node) - { - if (!IsInlineNode(node)) // skip over bold, italic, link, ect nodes - { - if (IsTextNode(node) && IsEditable(node)) - { - textNode = do_QueryInterface(node); - textNode->GetLength(&strLength); - if (strLength) - { - // you could use nsITextContent::IsOnlyWhitespace here - textNode->SubstringData(strLength-1,strLength,tempString); - *outIsSpace = nsCRT::IsAsciiSpace(tempString.First()); - *outIsNBSP = (tempString.First() == nbsp); - if (outNode) *outNode = do_QueryInterface(aParentNode); - if (outOffset) *outOffset = strLength-1; - return NS_OK; - } - // else it's an empty text node, or not editable; skip it. - } - else // node is an image or some other thingy that doesn't count as whitespace - { - break; - } - } - // otherwise we found a node we want to skip, keep going - tmp = node; - node = NextNodeInBlock(tmp, kIterBackward); - } - - return NS_OK; - -} - - /////////////////////////////////////////////////////////////////////////// // SplitNodeDeep: this splits a node "deeply", splitting children as // appropriate. The place to split is represented by diff --git a/mozilla/editor/libeditor/base/nsEditor.h b/mozilla/editor/libeditor/base/nsEditor.h index 0d0510b8713..c63be7c628f 100644 --- a/mozilla/editor/libeditor/base/nsEditor.h +++ b/mozilla/editor/libeditor/base/nsEditor.h @@ -37,10 +37,8 @@ #include "nsIDOMRange.h" #include "nsIPrivateTextRange.h" #include "nsITransactionManager.h" -#include "TransactionFactory.h" #include "nsIComponentManager.h" #include "nsISupportsArray.h" -#include "nsIEditProperty.h" #include "nsIDOMCharacterData.h" #include "nsICSSStyleSheet.h" #include "nsIDTD.h" @@ -72,7 +70,6 @@ class RemoveStyleSheetTxn; class nsIFile; class nsISelectionController; - /** implementation of an editor object. it will be the controller/focal point * for the main editor services. i.e. the GUIManager, publishing, transaction * manager, event interfaces. the idea for the event interfaces is to have them @@ -483,15 +480,6 @@ public: nsCOMPtr<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); - - /** set aIsBlock to PR_TRUE if aNode is block as defined by HTML DTD */ - static nsresult IsNodeBlock(nsIDOMNode *aNode, PRBool &aIsBlock); - - /** This version is for exposure to JavaScript */ - NS_IMETHOD NodeIsBlock(nsIDOMNode *aNode, PRBool &aIsBlock); - /** 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. @@ -601,51 +589,12 @@ public: static nsresult GetTagString(nsIDOMNode *aNode, nsString& outString); static nsCOMPtr<nsIAtom> GetTag(nsIDOMNode *aNode); static PRBool NodesSameType(nsIDOMNode *aNode1, nsIDOMNode *aNode2); - static PRBool IsBlockNode(nsIDOMNode *aNode); - static PRBool IsInlineNode(nsIDOMNode *aNode); - static nsCOMPtr<nsIDOMNode> GetBlockNodeParent(nsIDOMNode *aNode); - static PRBool HasSameBlockNodeParent(nsIDOMNode *aNode1, nsIDOMNode *aNode2); - /** Determines the bounding nodes for the block section containing aNode. - * The calculation is based on some nodes intrinsically being block elements - * acording to HTML. Style sheets are not considered in this calculation. - * <BR> tags separate block content sections. So the HTML markup: - * <PRE> - * <P>text1<BR>text2<B>text3</B></P> - * </PRE> - * contains two block content sections. The first has the text node "text1" - * for both endpoints. The second has "text2" as the left endpoint and - * "text3" as the right endpoint. - * Notice that offsets aren't required, only leaf nodes. Offsets are implicit. - * - * @param aNode the block content returned includes aNode - * @param aLeftNode [OUT] the left endpoint of the block content containing aNode - * @param aRightNode [OUT] the right endpoint of the block content containing aNode - * - */ - static nsresult GetBlockSection(nsIDOMNode *aNode, - nsIDOMNode **aLeftNode, - nsIDOMNode **aRightNode); - - /** Compute the set of block sections in a given range. - * A block section is the set of (leftNode, rightNode) pairs given - * by GetBlockSection. The set is computed by computing the - * block section for every leaf node in the range and throwing - * out duplicates. - * - * @param aRange The range to compute block sections for. - * @param aSections Allocated storage for the resulting set, stored as nsIDOMRanges. - */ - static nsresult GetBlockSectionsForRange(nsIDOMRange *aRange, - nsISupportsArray *aSections); - - static PRBool IsTextOrElementNode(nsIDOMNode *aNode); static PRBool IsTextNode(nsIDOMNode *aNode); static PRInt32 GetIndexOf(nsIDOMNode *aParent, nsIDOMNode *aChild); static nsCOMPtr<nsIDOMNode> GetChildAt(nsIDOMNode *aParent, PRInt32 aOffset); - static nsCOMPtr<nsIDOMNode> NextNodeInBlock(nsIDOMNode *aNode, IterDirection aDir); static nsresult GetStartNodeAndOffset(nsISelection *aSelection, nsCOMPtr<nsIDOMNode> *outStartNode, PRInt32 *outStartOffset); static nsresult GetEndNodeAndOffset(nsISelection *aSelection, nsCOMPtr<nsIDOMNode> *outEndNode, PRInt32 *outEndOffset); @@ -663,18 +612,6 @@ public: nsresult ClearSelection(); nsresult IsPreformatted(nsIDOMNode *aNode, PRBool *aResult); - nsresult IsNextCharWhitespace(nsIDOMNode *aParentNode, - PRInt32 aOffset, - PRBool *outIsSpace, - PRBool *outIsNBSP, - nsCOMPtr<nsIDOMNode> *outNode = 0, - PRInt32 *outOffset = 0); - nsresult IsPrevCharWhitespace(nsIDOMNode *aParentNode, - PRInt32 aOffset, - PRBool *outIsSpace, - PRBool *outIsNBSP, - nsCOMPtr<nsIDOMNode> *outNode = 0, - PRInt32 *outOffset = 0); nsresult SplitNodeDeep(nsIDOMNode *aNode, nsIDOMNode *aSplitPointParent, @@ -693,6 +630,13 @@ public: PRBool GetShouldTxnSetSelection(); void SetShouldTxnSetSelection(PRBool aShould); +public: + // Argh! These transaction names are used by PlaceholderTxn and + // nsPlaintextEditor. They should be localized to those classes. + static nsIAtom *gTypingTxnName; + static nsIAtom *gIMETxnName; + static nsIAtom *gDeleteTxnName; + protected: PRUint32 mFlags; // behavior flags. See nsPlaintextEditor.h for the flags we use. @@ -702,7 +646,6 @@ protected: nsIViewManager *mViewManager; PRInt32 mUpdateCount; nsCOMPtr<nsITransactionManager> mTxnMgr; - nsCOMPtr<nsIEditProperty> mEditProperty; nsCOMPtr<nsICSSStyleSheet> mLastStyleSheet; // is owning this dangerous? nsWeakPtr mPlaceHolderTxn; // weak reference to placeholder for begin/end batch purposes nsIAtom *mPlaceHolderName; // name of placeholder transaction diff --git a/mozilla/editor/libeditor/base/nsEditorController.cpp b/mozilla/editor/libeditor/base/nsEditorController.cpp index 331850b8307..5d4c0c908ae 100644 --- a/mozilla/editor/libeditor/base/nsEditorController.cpp +++ b/mozilla/editor/libeditor/base/nsEditorController.cpp @@ -26,20 +26,8 @@ #include "nsIComponentManager.h" #include "nsEditorController.h" #include "nsIEditor.h" -#include "nsIEditorShell.h" -#include "nsIEditorMailSupport.h" -#include "nsIFormControlFrame.h" -#include "nsISelection.h" -#include "nsIHTMLEditor.h" -#include "nsISupportsPrimitives.h" -#include "nsXPIDLString.h" - -#include "nsISelectionController.h" -#include "nsIDocument.h" -#include "nsIPresShell.h" #include "nsEditorCommands.h" -#include "nsComposerCommands.h" NS_IMPL_ADDREF(nsEditorController) @@ -246,102 +234,3 @@ nsresult nsEditorController::GetEditorCommandManager(nsIControllerCommandManager return NS_OK; } - - -#ifdef XP_MAC -#pragma mark - -#endif - -nsComposerController::nsComposerController() -{ -} - -nsComposerController::~nsComposerController() -{ -} - -NS_IMETHODIMP nsComposerController::Init(nsISupports *aCommandRefCon) -{ - nsresult rv; - - rv = nsEditorController::Init(aCommandRefCon); - if (NS_FAILED(rv)) return rv; - - mCommandManager = do_CreateInstance("@mozilla.org/content/controller-command-manager;1", &rv); - if (NS_FAILED(rv)) return rv; - - // register the commands. - rv = nsComposerController::RegisterComposerCommands(mCommandManager); - if (NS_FAILED(rv)) return rv; - - return NS_OK; -} - -#define NS_REGISTER_STYLE_COMMAND(_cmdClass, _cmdName, _styleTag) \ - { \ - _cmdClass* theCmd = new _cmdClass(_styleTag); \ - if (!theCmd) return NS_ERROR_OUT_OF_MEMORY; \ - rv = inCommandManager->RegisterCommand(NS_LITERAL_STRING(_cmdName), \ - NS_STATIC_CAST(nsIControllerCommand *, theCmd)); \ - } - - -// static -nsresult nsComposerController::RegisterComposerCommands(nsIControllerCommandManager *inCommandManager) -{ - nsresult rv; - - // File menu - NS_REGISTER_FIRST_COMMAND(nsPrintingCommands, "cmd_print"); - NS_REGISTER_NEXT_COMMAND(nsPrintingCommands, "cmd_printSetup"); - NS_REGISTER_NEXT_COMMAND(nsPrintingCommands,"cmd_print_button"); - NS_REGISTER_LAST_COMMAND(nsPrintingCommands, "cmd_printPreview"); - - // Edit menu - NS_REGISTER_ONE_COMMAND(nsPasteQuotationCommand, "cmd_pasteQuote"); - - // indent/outdent - NS_REGISTER_ONE_COMMAND(nsIndentCommand, "cmd_indent"); - NS_REGISTER_ONE_COMMAND(nsOutdentCommand, "cmd_outdent"); - - // Styles - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_bold", "b"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_italic", "i"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_underline", "u"); - - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_strikethrough", "strike"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_superscript", "sup"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_subscript", "sub"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_nobreak", "nobr"); - - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_em", "em"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_strong", "strong"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_cite", "cite"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_abbr", "abbr"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_acronym", "acronym"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_code", "code"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_samp", "samp"); - NS_REGISTER_STYLE_COMMAND(nsStyleUpdatingCommand, "cmd_var", "var"); - - // lists - NS_REGISTER_STYLE_COMMAND(nsListCommand, "cmd_ol", "ol"); - NS_REGISTER_STYLE_COMMAND(nsListCommand, "cmd_ul", "ul"); - NS_REGISTER_STYLE_COMMAND(nsListItemCommand, "cmd_dt", "dt"); - NS_REGISTER_STYLE_COMMAND(nsListItemCommand, "cmd_dd", "dd"); - NS_REGISTER_ONE_COMMAND(nsRemoveListCommand, "cmd_removeList"); - - // format stuff - NS_REGISTER_ONE_COMMAND(nsParagraphStateCommand, "cmd_paragraphState"); - NS_REGISTER_ONE_COMMAND(nsFontFaceStateCommand, "cmd_fontFace"); - NS_REGISTER_ONE_COMMAND(nsFontColorStateCommand, "cmd_fontColor"); - NS_REGISTER_ONE_COMMAND(nsBackgroundColorStateCommand, "cmd_backgroundColor"); - - NS_REGISTER_ONE_COMMAND(nsAlignCommand, "cmd_align"); - NS_REGISTER_ONE_COMMAND(nsRemoveStylesCommand, "cmd_removeStyles"); - - NS_REGISTER_ONE_COMMAND(nsIncreaseFontSizeCommand, "cmd_increaseFont"); - NS_REGISTER_ONE_COMMAND(nsDecreaseFontSizeCommand, "cmd_decreaseFont"); - - return NS_OK; -} - diff --git a/mozilla/editor/libeditor/base/nsEditorController.h b/mozilla/editor/libeditor/base/nsEditorController.h index 5546bb702eb..dbf3f9e3982 100644 --- a/mozilla/editor/libeditor/base/nsEditorController.h +++ b/mozilla/editor/libeditor/base/nsEditorController.h @@ -20,12 +20,12 @@ * Contributor(s): */ +#ifndef nsEditorController_h__ +#define nsEditorController_h__ + #define NS_EDITORCONTROLLER_CID \ { 0x26fb965c, 0x9de6, 0x11d3, { 0xbc, 0xcc, 0x0, 0x60, 0xb0, 0xfc, 0x76, 0xbd } } -#define NS_COMPOSERCONTROLLER_CID \ -{ 0x50e95301, 0x17a8, 0x11d4, { 0x9f, 0x7e, 0xdd, 0x53, 0x0d, 0x5f, 0x05, 0x7c } } - #include "nsIController.h" #include "nsIEditorController.h" @@ -37,7 +37,6 @@ #include "nsWeakPtr.h" class nsIEditor; -class nsIEditorShell; // the editor controller is used for both text widgets, and basic text editing @@ -91,23 +90,5 @@ private: }; +#endif /* nsEditorController_h__ */ - -// the editor controller is used for composer only (and other HTML compose -// areas). The refCon that gets passed to its commands is an nsIEditorShell. - -class nsComposerController : public nsEditorController -{ -public: - - nsComposerController(); - virtual ~nsComposerController(); - - /** init the controller */ - NS_IMETHOD Init(nsISupports *aCommandRefCon); - -private: - - static nsresult RegisterComposerCommands(nsIControllerCommandManager* inCommandManager); - -}; diff --git a/mozilla/editor/libeditor/base/nsEditorUtils.h b/mozilla/editor/libeditor/base/nsEditorUtils.h index 4827800df70..8fb8407a443 100644 --- a/mozilla/editor/libeditor/base/nsEditorUtils.h +++ b/mozilla/editor/libeditor/base/nsEditorUtils.h @@ -32,9 +32,10 @@ #include "nsIAtom.h" #include "nsVoidArray.h" #include "nsEditor.h" -#include "nsPlaintextEditor.h" #include "nsIContentIterator.h" +class nsPlaintextEditor; + /*************************************************************************** * stack based helper class for batching a collection of txns inside a * placeholder txn. @@ -49,23 +50,6 @@ class nsAutoPlaceHolderBatch ~nsAutoPlaceHolderBatch() { if (mEd) mEd->EndPlaceHolderTransaction(); } }; -/*************************************************************************** - * stack based helper class for detecting end of editor initialization, in - * order to triger "end of init" initialization of the edit rules. - */ -class nsAutoEditInitRulesTrigger -{ - private: - nsPlaintextEditor *mEd; - nsresult &mRes; - public: - nsAutoEditInitRulesTrigger( nsPlaintextEditor *aEd, nsresult &aRes) : mEd(aEd), mRes(aRes) - { if (mEd) mEd->BeginEditorInit(); } - ~nsAutoEditInitRulesTrigger() { if (mEd) mRes = mEd->EndEditorInit(); } -}; - - - /*************************************************************************** * stack based helper class for batching a collection of txns. * Note: I changed this to use placeholder batching so that we get diff --git a/mozilla/editor/libeditor/build/nsEditorRegistration.cpp b/mozilla/editor/libeditor/build/nsEditorRegistration.cpp index f262c18cdd5..df7e4b59ee5 100644 --- a/mozilla/editor/libeditor/build/nsEditorRegistration.cpp +++ b/mozilla/editor/libeditor/build/nsEditorRegistration.cpp @@ -23,23 +23,33 @@ #include "nsIGenericFactory.h" #include "nsEditorCID.h" -#include "nsEditorShell.h" // for the CID #include "nsEditor.h" // for gInstanceCount -#include "nsEditorController.h" //CID #include "nsEditorService.h" +#include "nsHTMLEditor.h" #include "nsPlaintextEditor.h" +#include "nsEditorController.h" //CID + +#define DO_COMPOSER_TOO 1 +#ifdef DO_COMPOSER_TOO +#include "nsComposerController.h" //CID +#include "nsEditorShell.h" // for the CID +#endif /* DO_COMPOSER_TOO */ + + //////////////////////////////////////////////////////////////////////// // Define the contructor function for the objects // // NOTE: This creates an instance of objects by using the default constructor // -NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorShell) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorController) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsComposerController) NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorService) NS_GENERIC_FACTORY_CONSTRUCTOR(nsPlaintextEditor) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorController) +#ifdef DO_COMPOSER_TOO +NS_GENERIC_FACTORY_CONSTRUCTOR(nsComposerController) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorShell) +#endif /* DO_COMPOSER_TOO */ #ifdef ENABLE_EDITOR_API_LOG #include "nsHTMLEditorLog.h" @@ -63,14 +73,6 @@ static nsModuleComponentInfo components[] = { { "HTML Editor", NS_HTMLEDITOR_CID, "@mozilla.org/editor/htmleditor;1", nsHTMLEditorConstructor, }, #endif - { "Editor Controller", NS_EDITORCONTROLLER_CID, - "@mozilla.org/editor/editorcontroller;1", nsEditorControllerConstructor, }, - { "Composer Controller", NS_COMPOSERCONTROLLER_CID, - "@mozilla.org/editor/composercontroller;1", nsComposerControllerConstructor, }, - { "Editor Shell Component", NS_EDITORSHELL_CID, - "@mozilla.org/editor/editorshell;1", nsEditorShellConstructor, }, - { "Editor Shell Spell Checker", NS_EDITORSHELL_CID, - "@mozilla.org/editor/editorspellcheck;1", nsEditorShellConstructor, }, { "Editor Service", NS_EDITORSERVICE_CID, "@mozilla.org/editor/editorservice;1", nsEditorServiceConstructor,}, { "Editor Startup Handler", NS_EDITORSERVICE_CID, @@ -81,6 +83,18 @@ static nsModuleComponentInfo components[] = { { "Edit Startup Handler", NS_EDITORSERVICE_CID, "@mozilla.org/commandlinehandler/general-startup;1?type=edit", nsEditorServiceConstructor, }, + { "Editor Controller", NS_EDITORCONTROLLER_CID, + "@mozilla.org/editor/editorcontroller;1", + nsEditorControllerConstructor, }, +#ifdef DO_COMPOSER_TOO + { "Composer Controller", NS_COMPOSERCONTROLLER_CID, + "@mozilla.org/editor/composercontroller;1", + nsComposerControllerConstructor, }, + { "Editor Shell Component", NS_EDITORSHELL_CID, + "@mozilla.org/editor/editorshell;1", nsEditorShellConstructor, }, + { "Editor Shell Spell Checker", NS_EDITORSHELL_CID, + "@mozilla.org/editor/editorspellcheck;1", nsEditorShellConstructor, }, +#endif /* DO_COMPOSER_TOO */ }; //////////////////////////////////////////////////////////////////////// diff --git a/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp b/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp index d6894dc2b59..217207bd770 100644 --- a/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp @@ -23,6 +23,7 @@ #include "nsHTMLEditor.h" #include "nsHTMLEditRules.h" +#include "nsTextEditUtils.h" #include "nsHTMLEditUtils.h" #include "nsEditorEventListeners.h" @@ -81,7 +82,6 @@ #include "nsAOLCiter.h" #include "nsInternetCiter.h" #include "nsISupportsPrimitives.h" -#include "InsertTextTxn.h" // netwerk #include "nsIURI.h" @@ -94,10 +94,6 @@ #include "nsIDragService.h" #include "nsIDOMNSUIEvent.h" -// Transactionas -#include "PlaceholderTxn.h" -#include "nsStyleSheetTxns.h" - // Misc #include "TextEditorTest.h" #include "nsEditorUtils.h" @@ -466,7 +462,7 @@ nsresult nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsString& aInputStr NS_ENSURE_TRUE(curNode, NS_ERROR_FAILURE); NS_ENSURE_TRUE(curNode != fragmentAsNode, NS_ERROR_FAILURE); - NS_ENSURE_TRUE(!nsHTMLEditUtils::IsBody(curNode), NS_ERROR_FAILURE); + NS_ENSURE_TRUE(!nsTextEditUtils::IsBody(curNode), NS_ERROR_FAILURE); if (insertedContextParent) { @@ -512,7 +508,7 @@ nsresult nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsString& aInputStr while (NS_FAILED(res) && curNode) { curNode->GetParentNode(getter_AddRefs(parent)); - if (parent && !nsHTMLEditUtils::IsBody(parent)) + if (parent && !nsTextEditUtils::IsBody(parent)) { res = InsertNodeAtPoint(parent, parentNode, offsetOfNewNode, PR_TRUE); if (NS_SUCCEEDED(res)) @@ -1326,41 +1322,15 @@ NS_IMETHODIMP nsHTMLEditor::InsertAsQuotation(const nsString& aQuotedText, charset, aNodeInserted); } -// text insert. +// Insert plaintext as a quotation, with cite marks (e.g. "> "). +// This differs from its corresponding method in nsPlaintextEditor +// in that here, quoted material is enclosed in a <pre> tag +// in order to preserve the original line wrapping. NS_IMETHODIMP nsHTMLEditor::InsertAsPlaintextQuotation(const nsString& aQuotedText, nsIDOMNode **aNodeInserted) { - // We have the text. Cite it appropriately: - nsCOMPtr<nsICiter> citer; nsresult rv; - NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &rv); - if (NS_FAILED(rv)) return rv; - - char *citationType = 0; - rv = prefs->CopyCharPref("mail.compose.citationType", &citationType); - - if (NS_SUCCEEDED(rv) && citationType[0]) - { - if (!strncmp(citationType, "aol", 3)) - citer = new nsAOLCiter; - else - citer = new nsInternetCiter; - PL_strfree(citationType); - } - else - citer = new nsInternetCiter; - - // Let the citer quote it for us: - nsString quotedStuff; - rv = citer->GetCiteString(aQuotedText, quotedStuff); - if (!NS_SUCCEEDED(rv)) - return rv; - - // It's best to put a blank line after the quoted text so that mails - // written without thinking won't be so ugly. - quotedStuff.Append(PRUnichar('\n')); - nsCOMPtr<nsIDOMNode> preNode; // get selection nsCOMPtr<nsISelection> selection; @@ -1406,7 +1376,8 @@ nsHTMLEditor::InsertAsPlaintextQuotation(const nsString& aQuotedText, selection->Collapse(preNode, 0); } - rv = InsertText(quotedStuff.GetUnicode()); + //rv = InsertText(quotedStuff.GetUnicode()); + rv = nsPlaintextEditor::InsertAsQuotation(aQuotedText, aNodeInserted); if (aNodeInserted && NS_SUCCEEDED(rv)) { @@ -1570,7 +1541,7 @@ nsresult nsHTMLEditor::CreateDOMFragmentFromPaste(nsIDOMNSRange *aNSRange, PRInt32 err, sep; sep = aInfoStr.FindChar((PRUnichar)','); aInfoStr.Left(numstr1, sep); - aInfoStr.Mid(numstr2, sep+1, -1); + aInfoStr.Right(numstr2, sep+1); *outRangeStartHint = numstr1.ToInteger(&err) + contextDepth; *outRangeEndHint = numstr2.ToInteger(&err) + contextDepth; } diff --git a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp index 7d6a6d0902f..1d066339fd5 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp @@ -29,8 +29,10 @@ #include "nsHTMLEditRules.h" #include "nsEditor.h" +#include "nsTextEditUtils.h" #include "nsHTMLEditUtils.h" #include "nsHTMLEditor.h" +#include "TypeInState.h" #include "nsIContent.h" #include "nsIContentIterator.h" @@ -77,7 +79,18 @@ enum /******************************************************** * first some helpful funcotrs we will use ********************************************************/ - + +static PRBool IsBlockNode(nsIDOMNode* node) +{ + PRBool isBlock (PR_FALSE); + nsHTMLEditor::NodeIsBlockStatic(node, isBlock); + return isBlock; +} + +static PRBool IsInlineNode(nsIDOMNode* node) +{ + return !IsBlockNode(node); +} class nsTableCellAndListItemFunctor : public nsBoolDomIterFunctor { @@ -95,7 +108,7 @@ class nsBRNodeFunctor : public nsBoolDomIterFunctor public: virtual PRBool operator()(nsIDOMNode* aNode) // used to build list of all td's & th's iterator covers { - if (nsHTMLEditUtils::IsBreak(aNode)) return PR_TRUE; + if (nsTextEditUtils::IsBreak(aNode)) return PR_TRUE; return PR_FALSE; } }; @@ -759,7 +772,7 @@ nsHTMLEditRules::GetParagraphState(PRBool &aMixed, nsString &outFormat) nsAutoString format; nsCOMPtr<nsIAtom> atom = mHTMLEditor->GetTag(curNode); - if (mHTMLEditor->IsInlineNode(curNode)) + if (IsInlineNode(curNode)) { nsCOMPtr<nsIDOMNode> block = mHTMLEditor->GetBlockNodeParent(curNode); if (block) @@ -851,10 +864,10 @@ nsHTMLEditRules::WillInsert(nsISelection *aSelection, PRBool *aCancel) // get prior node res = mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, address_of(priorNode)); - if (NS_SUCCEEDED(res) && priorNode && nsHTMLEditUtils::IsMozBR(priorNode)) + if (NS_SUCCEEDED(res) && priorNode && nsTextEditUtils::IsMozBR(priorNode)) { nsCOMPtr<nsIDOMNode> block1, block2; - if (mHTMLEditor->IsBlockNode(selNode)) block1 = selNode; + if (IsBlockNode(selNode)) block1 = selNode; else block1 = mHTMLEditor->GetBlockNodeParent(selNode); block2 = mHTMLEditor->GetBlockNodeParent(priorNode); @@ -1153,7 +1166,7 @@ nsHTMLEditRules::WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBo // identify the block nsCOMPtr<nsIDOMNode> blockParent; - if (nsEditor::IsBlockNode(node)) + if (IsBlockNode(node)) blockParent = node; else blockParent = mHTMLEditor->GetBlockNodeParent(node); @@ -1199,7 +1212,7 @@ nsHTMLEditRules::WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBo // Then we stick to the left to aviod an uber caret. nsCOMPtr<nsIDOMNode> siblingNode; brNode->GetNextSibling(getter_AddRefs(siblingNode)); - if (siblingNode && mHTMLEditor->IsBlockNode(siblingNode)) + if (siblingNode && IsBlockNode(siblingNode)) selPriv->SetInterlinePosition(PR_FALSE); else selPriv->SetInterlinePosition(PR_TRUE); @@ -1408,7 +1421,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection, } return res; } - else if ( mHTMLEditor->IsInlineNode(priorNode) ) + else if ( IsInlineNode(priorNode) ) { // remember where we are PRInt32 offset; @@ -1471,7 +1484,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection, if (NS_FAILED(res)) return res; // if there is no next node, or it's not in the body, then cancel the deletion - if (!nextNode || !nsHTMLEditUtils::InBody(nextNode, mHTMLEditor)) + if (!nextNode || !nsTextEditUtils::InBody(nextNode, mHTMLEditor)) { *aCancel = PR_TRUE; return res; @@ -1519,7 +1532,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection, } return res; } - else if ( mHTMLEditor->IsInlineNode(nextNode) ) + else if ( IsInlineNode(nextNode) ) { PRInt32 offset; nsCOMPtr<nsIDOMNode> node; @@ -1615,7 +1628,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection, } if (maybeBreak && maybeBlock && - nsHTMLEditUtils::IsBreak(maybeBreak) && nsEditor::IsBlockNode(maybeBlock)) + nsTextEditUtils::IsBreak(maybeBreak) && IsBlockNode(maybeBlock)) nodeToDelete = maybeBreak; else if (aAction == nsIEditor::ePrevious) res = mHTMLEditor->GetPriorHTMLNode(startNode, startOffset, address_of(nodeToDelete)); @@ -1656,11 +1669,11 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection, // there is a br in front of it. If so, we must delete both. // else you get this: deletion code deletes mozBR, then selection // adjusting code puts it back in. doh - if (nsHTMLEditUtils::IsMozBR(nodeToDelete)) + if (nsTextEditUtils::IsMozBR(nodeToDelete)) { nsCOMPtr<nsIDOMNode> brNode; res = mHTMLEditor->GetPriorHTMLNode(nodeToDelete, address_of(brNode)); - if (nsHTMLEditUtils::IsBreak(brNode)) + if (nsTextEditUtils::IsBreak(brNode)) { // is brNode also a descendant of same block? nsCOMPtr<nsIDOMNode> block, brBlock; @@ -1717,12 +1730,12 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection, // // Should we be calling IsBlockNode() instead of IsBody() here? - if (nsHTMLEditUtils::IsBody(startNode)) + if (nsTextEditUtils::IsBody(startNode)) leftParent = startNode; else leftParent = mHTMLEditor->GetBlockNodeParent(startNode); - if (nsHTMLEditUtils::IsBody(endNode)) + if (nsTextEditUtils::IsBody(endNode)) rightParent = endNode; else rightParent = mHTMLEditor->GetBlockNodeParent(endNode); @@ -1936,7 +1949,7 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection, nsCOMPtr<nsISupports> isupports = dont_AddRef(arrayOfNodes->ElementAt(j)); nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) ); // if curNode is not a Break, we're done - if (!nsHTMLEditUtils::IsBreak(curNode)) + if (!nsTextEditUtils::IsBreak(curNode)) { bOnlyBreaks = PR_FALSE; break; @@ -2043,7 +2056,7 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection, if (NS_FAILED(res)) return res; // if curNode is a Break, delete it, and quit remembering prev list item - if (nsHTMLEditUtils::IsBreak(curNode)) + if (nsTextEditUtils::IsBreak(curNode)) { res = mHTMLEditor->DeleteNode(curNode); if (NS_FAILED(res)) return res; @@ -2051,7 +2064,7 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection, continue; } // if curNode is an empty inline container, delete it - else if (mHTMLEditor->IsInlineNode(curNode) && mHTMLEditor->IsContainer(curNode)) + else if (IsInlineNode(curNode) && mHTMLEditor->IsContainer(curNode)) { PRBool bEmpty; res = mHTMLEditor->IsEmptyNode(curNode, &bEmpty); @@ -2165,7 +2178,7 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection, nsCOMPtr<nsIDOMNode> listItem; if (!nsHTMLEditUtils::IsListItem(curNode)) { - if (nsEditor::IsInlineNode(curNode) && prevListItem) + if (IsInlineNode(curNode) && prevListItem) { // this is a continuation of some inline nodes that belong together in // the same list item. use prevListItem @@ -2187,7 +2200,7 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection, res = mHTMLEditor->InsertContainerAbove(curNode, address_of(listItem), itemType); } if (NS_FAILED(res)) return res; - if (nsEditor::IsInlineNode(curNode)) + if (IsInlineNode(curNode)) prevListItem = listItem; } } @@ -2625,7 +2638,7 @@ nsHTMLEditRules::WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool * // this is a hack until i think about outdent for real. nsCOMPtr<nsIDOMNode> n = curNode; nsCOMPtr<nsIDOMNode> tmp; - while (!nsHTMLEditUtils::IsBody(n)) + while (!nsTextEditUtils::IsBody(n)) { if (nsHTMLEditUtils::IsBlockquote(n)) { @@ -2726,7 +2739,7 @@ nsHTMLEditRules::CreateStyleForInsertText(nsISelection *aSelection, nsIDOMDocume if (NS_FAILED(res)) return res; // don't try to split br's... // note: probably should only split containers, but being more conservative in changes for now. - if (nsHTMLEditUtils::IsBreak(secondSplitParent)) + if (nsTextEditUtils::IsBreak(secondSplitParent)) { savedBR = secondSplitParent; savedBR->GetParentNode(getter_AddRefs(tmp)); @@ -2854,7 +2867,7 @@ nsHTMLEditRules::IsEmptyBlock(nsIDOMNode *aNode, // nsresult res = NS_OK; nsCOMPtr<nsIDOMNode> nodeToTest; - if (nsEditor::IsBlockNode(aNode)) nodeToTest = do_QueryInterface(aNode); + if (IsBlockNode(aNode)) nodeToTest = do_QueryInterface(aNode); // else nsCOMPtr<nsIDOMElement> block; // looks like I forgot to finish this. Wonder what I was going to do? @@ -2907,7 +2920,7 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection, { nsCOMPtr<nsISupports> isupports = dont_AddRef(arrayOfNodes->ElementAt(0)); nsCOMPtr<nsIDOMNode> theNode( do_QueryInterface(isupports ) ); - if (nsHTMLEditUtils::IsBreak(theNode)) + if (nsTextEditUtils::IsBreak(theNode)) { emptyDiv = PR_TRUE; } @@ -2925,14 +2938,14 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection, // creating extra lines, if possible. res = mHTMLEditor->GetNextHTMLNode(parent, offset, address_of(brNode)); if (NS_FAILED(res)) return res; - if (brNode && nsHTMLEditUtils::IsBreak(brNode)) + if (brNode && nsTextEditUtils::IsBreak(brNode)) { // making use of html structure... if next node after where // we are putting our div is not a block, then the br we // found is in same block we are, so its safe to consume it. res = mHTMLEditor->GetNextHTMLSibling(parent, offset, address_of(sib)); if (NS_FAILED(res)) return res; - if (!nsEditor::IsBlockNode(sib)) + if (!IsBlockNode(sib)) { res = mHTMLEditor->DeleteNode(brNode); if (NS_FAILED(res)) return res; @@ -3377,20 +3390,20 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt // back up through any prior inline nodes that // aren't across a <br> from us. - if (!nsEditor::IsBlockNode(node)) + if (!IsBlockNode(node)) { - nsCOMPtr<nsIDOMNode> block = nsEditor::GetBlockNodeParent(node); + nsCOMPtr<nsIDOMNode> block = nsHTMLEditor::GetBlockNodeParent(node); nsCOMPtr<nsIDOMNode> prevNode, prevNodeBlock; res = mHTMLEditor->GetPriorHTMLNode(node, address_of(prevNode)); while (prevNode && NS_SUCCEEDED(res)) { - prevNodeBlock = nsEditor::GetBlockNodeParent(prevNode); + prevNodeBlock = nsHTMLEditor::GetBlockNodeParent(prevNode); if (prevNodeBlock != block) break; - if (nsHTMLEditUtils::IsBreak(prevNode)) + if (nsTextEditUtils::IsBreak(prevNode)) break; - if (nsEditor::IsBlockNode(prevNode)) + if (IsBlockNode(prevNode)) break; node = prevNode; res = mHTMLEditor->GetPriorHTMLNode(node, address_of(prevNode)); @@ -3399,11 +3412,11 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt // finding the real start for this point. look up the tree for as long as we are the // first node in the container, and as long as we haven't hit the body node. - if (!nsHTMLEditUtils::IsBody(node)) + if (!nsTextEditUtils::IsBody(node)) { res = nsEditor::GetNodeLocation(node, address_of(parent), &offset); if (NS_FAILED(res)) return res; - while ((IsFirstNode(node)) && (!nsHTMLEditUtils::IsBody(parent))) + while ((IsFirstNode(node)) && (!nsTextEditUtils::IsBody(parent))) { // some cutoffs are here: we don't need to also include them in the aWhere == kEnd case. // as long as they are in one or the other it will work. @@ -3443,23 +3456,23 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt // look ahead through any further inline nodes that // aren't across a <br> from us, and that are enclosed in the same block. - if (!nsEditor::IsBlockNode(node)) + if (!IsBlockNode(node)) { - nsCOMPtr<nsIDOMNode> block = nsEditor::GetBlockNodeParent(node); + nsCOMPtr<nsIDOMNode> block = nsHTMLEditor::GetBlockNodeParent(node); nsCOMPtr<nsIDOMNode> nextNode, nextNodeBlock; res = mHTMLEditor->GetNextHTMLNode(node, address_of(nextNode)); while (nextNode && NS_SUCCEEDED(res)) { - nextNodeBlock = nsEditor::GetBlockNodeParent(nextNode); + nextNodeBlock = nsHTMLEditor::GetBlockNodeParent(nextNode); if (nextNodeBlock != block) break; - if (nsHTMLEditUtils::IsBreak(nextNode)) + if (nsTextEditUtils::IsBreak(nextNode)) { node = nextNode; break; } - if (nsEditor::IsBlockNode(nextNode)) + if (IsBlockNode(nextNode)) break; node = nextNode; res = mHTMLEditor->GetNextHTMLNode(node, address_of(nextNode)); @@ -3468,11 +3481,11 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt // finding the real end for this point. look up the tree for as long as we are the // last node in the container, and as long as we haven't hit the body node. - if (!nsHTMLEditUtils::IsBody(node)) + if (!nsTextEditUtils::IsBody(node)) { res = nsEditor::GetNodeLocation(node, address_of(parent), &offset); if (NS_FAILED(res)) return res; - while ((IsLastNode(node)) && (!nsHTMLEditUtils::IsBody(parent))) + while ((IsLastNode(node)) && (!nsTextEditUtils::IsBody(parent))) { node = parent; res = nsEditor::GetNodeLocation(node, address_of(parent), &offset); @@ -3708,7 +3721,7 @@ nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges, { isupports = dont_AddRef((*outArrayOfNodes)->ElementAt(i)); nsCOMPtr<nsIDOMNode> node( do_QueryInterface(isupports) ); - if (!aDontTouchContent && mHTMLEditor->IsInlineNode(node) + if (!aDontTouchContent && IsInlineNode(node) && mHTMLEditor->IsContainer(node) && !mHTMLEditor->IsTextNode(node)) { nsCOMPtr<nsISupportsArray> arrayOfInlines; @@ -4076,10 +4089,10 @@ nsCOMPtr<nsIDOMNode> nsHTMLEditRules::GetHighestInlineParent(nsIDOMNode* aNode) { if (!aNode) return nsnull; - if (nsEditor::IsBlockNode(aNode)) return nsnull; + if (IsBlockNode(aNode)) return nsnull; nsCOMPtr<nsIDOMNode> inlineNode, node=aNode; - while (node && mHTMLEditor->IsInlineNode(node)) + while (node && IsInlineNode(node)) { inlineNode = node; inlineNode->GetParentNode(getter_AddRefs(node)); @@ -4217,7 +4230,7 @@ nsHTMLEditRules::ReturnInHeader(nsISelection *aSelection, nsCOMPtr<nsIDOMNode> sibling; res = mHTMLEditor->GetNextHTMLSibling(headerParent, offset+1, address_of(sibling)); if (NS_FAILED(res)) return res; - if (!sibling || !nsHTMLEditUtils::IsBreak(sibling)) + if (!sibling || !nsTextEditUtils::IsBreak(sibling)) { res = CreateMozBR(headerParent, offset+1, address_of(sibling)); if (NS_FAILED(res)) return res; @@ -4274,8 +4287,8 @@ nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection, // just fall out to default of inserting a BR return res; } - if (nsHTMLEditUtils::IsBreak(sibling) - && !nsHTMLEditUtils::HasMozAttr(sibling)) + if (nsTextEditUtils::IsBreak(sibling) + && !nsTextEditUtils::HasMozAttr(sibling)) { PRInt32 newOffset; *aCancel = PR_TRUE; @@ -4312,8 +4325,8 @@ nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection, // just fall out to default of inserting a BR return res; } - if (nsHTMLEditUtils::IsBreak(sibling) - && !nsHTMLEditUtils::HasMozAttr(sibling)) + if (nsTextEditUtils::IsBreak(sibling) + && !nsTextEditUtils::HasMozAttr(sibling)) { PRInt32 newOffset; *aCancel = PR_TRUE; @@ -4340,14 +4353,14 @@ nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection, nsCOMPtr<nsIDOMNode> nearNode; res = mHTMLEditor->GetPriorHTMLNode(aNode, aOffset, address_of(nearNode)); if (NS_FAILED(res)) return res; - if (!nearNode || !nsHTMLEditUtils::IsBreak(nearNode) - || nsHTMLEditUtils::HasMozAttr(nearNode)) + if (!nearNode || !nsTextEditUtils::IsBreak(nearNode) + || nsTextEditUtils::HasMozAttr(nearNode)) { // is there a BR after to it? res = mHTMLEditor->GetNextHTMLNode(aNode, aOffset, address_of(nearNode)); if (NS_FAILED(res)) return res; - if (!nearNode || !nsHTMLEditUtils::IsBreak(nearNode) - || nsHTMLEditUtils::HasMozAttr(nearNode)) + if (!nearNode || !nsTextEditUtils::IsBreak(nearNode) + || nsTextEditUtils::HasMozAttr(nearNode)) { // just fall out to default of inserting a BR return res; @@ -4658,7 +4671,7 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString // arrayOfNodes is contructed, but some additional logic should // be added here if that should change - else if (nsEditor::IsInlineNode(curNode) && !bNoParent) + else if (IsInlineNode(curNode) && !bNoParent) { // if curNode is a non editable, drop it if we are going to <pre> if ((aBlockTag->EqualsWithConversion("pre")) && (!mHTMLEditor->IsEditable(curNode))) @@ -4743,9 +4756,9 @@ nsHTMLEditRules::AddTerminatingBR(nsIDOMNode *aBlock) if (!aBlock) return NS_ERROR_NULL_POINTER; nsCOMPtr<nsIDOMNode> last; nsresult res = mHTMLEditor->GetLastEditableLeaf(aBlock, address_of(last)); - if (last && nsHTMLEditUtils::IsBreak(last)) + if (last && nsTextEditUtils::IsBreak(last)) { - if (nsHTMLEditUtils::IsMozBR(last)) + if (nsTextEditUtils::IsMozBR(last)) { // need to convert a br nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(last); @@ -4872,7 +4885,7 @@ nsHTMLEditRules::GetTopEnclosingMailCite(nsIDOMNode *aNode, if ( (aPlainText && nsHTMLEditUtils::IsPre(node)) || (!aPlainText && nsHTMLEditUtils::IsMailCite(node)) ) *aOutCiteNode = node; - if (nsHTMLEditUtils::IsBody(node)) break; + if (nsTextEditUtils::IsBody(node)) break; res = node->GetParentNode(getter_AddRefs(parentNode)); if (NS_FAILED(res)) return res; @@ -5021,13 +5034,13 @@ nsHTMLEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection // is nearNode also a descendant of same block? nsCOMPtr<nsIDOMNode> block, nearBlock; - if (mHTMLEditor->IsBlockNode(selNode)) block = selNode; + if (IsBlockNode(selNode)) block = selNode; else block = mHTMLEditor->GetBlockNodeParent(selNode); nearBlock = mHTMLEditor->GetBlockNodeParent(nearNode); if (block == nearBlock) { - if (nearNode && nsHTMLEditUtils::IsBreak(nearNode) - && !nsHTMLEditUtils::IsMozBR(nearNode)) + if (nearNode && nsTextEditUtils::IsBreak(nearNode) + && !nsTextEditUtils::IsMozBR(nearNode)) { PRBool bIsLast; res = mHTMLEditor->IsLastEditableChild(nearNode, &bIsLast); @@ -5058,7 +5071,7 @@ nsHTMLEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection if (NS_FAILED(res)) return res; res = mHTMLEditor->GetNextHTMLSibling(nearNode, address_of(nextNode)); if (NS_FAILED(res)) return res; - if (nextNode && mHTMLEditor->IsBlockNode(nextNode)) + if (nextNode && IsBlockNode(nextNode)) { // need to insert special moz BR. Why? Because if we don't // the user will see no new line for the break. @@ -5079,12 +5092,12 @@ nsHTMLEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection // we aren't in a textnode: are we adjacent to a break or an image? res = mHTMLEditor->GetPriorHTMLSibling(selNode, selOffset, address_of(nearNode)); if (NS_FAILED(res)) return res; - if (nearNode && (nsHTMLEditUtils::IsBreak(nearNode) + if (nearNode && (nsTextEditUtils::IsBreak(nearNode) || nsHTMLEditUtils::IsImage(nearNode))) return NS_OK; // this is a good place for the caret to be res = mHTMLEditor->GetNextHTMLSibling(selNode, selOffset, address_of(nearNode)); if (NS_FAILED(res)) return res; - if (nearNode && (nsHTMLEditUtils::IsBreak(nearNode) + if (nearNode && (nsTextEditUtils::IsBreak(nearNode) || nsHTMLEditUtils::IsImage(nearNode))) return NS_OK; // this is a good place for the caret to be @@ -5136,7 +5149,7 @@ nsHTMLEditRules::FindNearSelectableNode(nsIDOMNode *aSelNode, // scan in the right direction until we find an eligible text node, // but dont cross any breaks, images, or table elements. while (nearNode && !(mHTMLEditor->IsTextNode(nearNode) - || nsHTMLEditUtils::IsBreak(nearNode) + || nsTextEditUtils::IsBreak(nearNode) || nsHTMLEditUtils::IsImage(nearNode))) { curNode = nearNode; @@ -5226,7 +5239,7 @@ nsHTMLEditRules::RemoveEmptyNodes() PRBool bIsEmptyNode; res = mHTMLEditor->IsEmptyNode(node, &bIsEmptyNode, PR_FALSE, PR_TRUE); if (NS_FAILED(res)) return res; - if (bIsEmptyNode && !nsHTMLEditUtils::IsBody(node)) + if (bIsEmptyNode && !nsTextEditUtils::IsBody(node)) { if (nsHTMLEditUtils::IsParagraph(node) || nsHTMLEditUtils::IsHeader(node) || @@ -5564,7 +5577,7 @@ nsHTMLEditRules::ConfirmSelectionInBody() temp = selNode; // check that selNode is inside body - while (temp && !nsHTMLEditUtils::IsBody(temp)) + while (temp && !nsTextEditUtils::IsBody(temp)) { res = temp->GetParentNode(getter_AddRefs(parent)); temp = parent; @@ -5584,7 +5597,7 @@ nsHTMLEditRules::ConfirmSelectionInBody() temp = selNode; // check that selNode is inside body - while (temp && !nsHTMLEditUtils::IsBody(temp)) + while (temp && !nsTextEditUtils::IsBody(temp)) { res = temp->GetParentNode(getter_AddRefs(parent)); temp = parent; @@ -5654,7 +5667,7 @@ nsresult nsHTMLEditRules::InsertMozBRIfNeeded(nsIDOMNode *aNode) { if (!aNode) return NS_ERROR_NULL_POINTER; - if (!mHTMLEditor->IsBlockNode(aNode)) return NS_OK; + if (!IsBlockNode(aNode)) return NS_OK; PRBool isEmpty; nsCOMPtr<nsIDOMNode> brNode; diff --git a/mozilla/editor/libeditor/html/nsHTMLEditUtils.cpp b/mozilla/editor/libeditor/html/nsHTMLEditUtils.cpp index 97d5201f2ff..7978e5cf12e 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditUtils.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditUtils.cpp @@ -21,6 +21,7 @@ */ #include "nsHTMLEditUtils.h" +#include "nsTextEditUtils.h" #include "nsString.h" #include "nsEditor.h" @@ -28,124 +29,21 @@ #include "nsIDOMNodeList.h" #include "nsIDOMHTMLAnchorElement.h" -PRBool -nsHTMLEditUtils::NodeIsType(nsIDOMNode *aNode, const nsAReadableString& aTag) -{ - NS_PRECONDITION(aNode, "null node passed to nsHTMLEditUtils::NodeIsType"); - if (aNode) - { - nsAutoString tag; - nsEditor::GetTagString(aNode,tag); - tag.ToLowerCase(); - if (tag.Equals(aTag)) - return PR_TRUE; - } - return PR_FALSE; -} - -/******************************************************** - * helper methods from nsTextEditRules - ********************************************************/ - /////////////////////////////////////////////////////////////////////////// -// IsBody: true if node an html body node -// -PRBool -nsHTMLEditUtils::IsBody(nsIDOMNode *node) -{ - return NodeIsType(node, NS_LITERAL_STRING("body")); -} - - - -/////////////////////////////////////////////////////////////////////////// -// IsBreak: true if node an html break node -// -PRBool -nsHTMLEditUtils::IsBreak(nsIDOMNode *node) -{ - return NodeIsType(node, NS_LITERAL_STRING("br")); -} - - -/////////////////////////////////////////////////////////////////////////// -// IsBreak: true if node an html break node // PRBool nsHTMLEditUtils::IsBig(nsIDOMNode *node) { - return NodeIsType(node, NS_LITERAL_STRING("big")); + return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("big")); } /////////////////////////////////////////////////////////////////////////// -// IsBreak: true if node an html break node // PRBool nsHTMLEditUtils::IsSmall(nsIDOMNode *node) { - return NodeIsType(node, NS_LITERAL_STRING("small")); -} - - -/////////////////////////////////////////////////////////////////////////// -// IsMozBR: true if node an html br node with type = _moz -// -PRBool -nsHTMLEditUtils::IsMozBR(nsIDOMNode *node) -{ - NS_PRECONDITION(node, "null node passed to nsHTMLEditUtils::IsMozBR"); - if (IsBreak(node) && HasMozAttr(node)) return PR_TRUE; - return PR_FALSE; -} - - -/////////////////////////////////////////////////////////////////////////// -// HasMozAttr: true if node has type attribute = _moz -// (used to indicate the div's and br's we use in -// mail compose rules) -// -PRBool -nsHTMLEditUtils::HasMozAttr(nsIDOMNode *node) -{ - NS_PRECONDITION(node, "null parent passed to nsHTMLEditUtils::HasMozAttr"); - nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(node); - if (elem) - { - nsAutoString typeAttrName; typeAttrName.AssignWithConversion("type"); - nsAutoString typeAttrVal; - nsresult res = elem->GetAttribute(typeAttrName, typeAttrVal); - typeAttrVal.ToLowerCase(); - if (NS_SUCCEEDED(res) && (typeAttrVal.EqualsWithConversion("_moz"))) - return PR_TRUE; - } - return PR_FALSE; -} - - -/////////////////////////////////////////////////////////////////////////// -// InBody: true if node is a descendant of the body -// -PRBool -nsHTMLEditUtils::InBody(nsIDOMNode *node, nsIEditor *editor) -{ - if ( node ) - { - nsCOMPtr<nsIDOMElement> bodyElement; - nsresult res = editor->GetRootElement(getter_AddRefs(bodyElement)); - if (NS_FAILED(res) || !bodyElement) - return res?res:NS_ERROR_NULL_POINTER; - nsCOMPtr<nsIDOMNode> bodyNode = do_QueryInterface(bodyElement); - nsCOMPtr<nsIDOMNode> tmp; - nsCOMPtr<nsIDOMNode> p = node; - while (p && p!= bodyNode) - { - if (NS_FAILED(p->GetParentNode(getter_AddRefs(tmp))) || !tmp) - return PR_FALSE; - p = tmp; - } - } - return PR_TRUE; + return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("small")); } @@ -182,7 +80,7 @@ nsHTMLEditUtils::IsHeader(nsIDOMNode *node) PRBool nsHTMLEditUtils::IsParagraph(nsIDOMNode *node) { - return NodeIsType(node, NS_LITERAL_STRING("p")); + return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("p")); } @@ -232,7 +130,7 @@ nsHTMLEditUtils::IsTableElement(nsIDOMNode *node) PRBool nsHTMLEditUtils::IsTable(nsIDOMNode *node) { - return NodeIsType(node, NS_LITERAL_STRING("table")); + return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("table")); } /////////////////////////////////////////////////////////////////////////// @@ -241,7 +139,7 @@ nsHTMLEditUtils::IsTable(nsIDOMNode *node) PRBool nsHTMLEditUtils::IsTableRow(nsIDOMNode *node) { - return NodeIsType(node, NS_LITERAL_STRING("tr")); + return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("tr")); } @@ -309,7 +207,7 @@ nsHTMLEditUtils::IsList(nsIDOMNode *node) PRBool nsHTMLEditUtils::IsOrderedList(nsIDOMNode *node) { - return NodeIsType(node, NS_LITERAL_STRING("ol")); + return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("ol")); } @@ -319,7 +217,7 @@ nsHTMLEditUtils::IsOrderedList(nsIDOMNode *node) PRBool nsHTMLEditUtils::IsUnorderedList(nsIDOMNode *node) { - return NodeIsType(node, NS_LITERAL_STRING("ul")); + return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("ul")); } @@ -329,7 +227,7 @@ nsHTMLEditUtils::IsUnorderedList(nsIDOMNode *node) PRBool nsHTMLEditUtils::IsDefinitionList(nsIDOMNode *node) { - return NodeIsType(node, NS_LITERAL_STRING("dl")); + return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("dl")); } @@ -339,7 +237,7 @@ nsHTMLEditUtils::IsDefinitionList(nsIDOMNode *node) PRBool nsHTMLEditUtils::IsBlockquote(nsIDOMNode *node) { - return NodeIsType(node, NS_LITERAL_STRING("blockquote")); + return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("blockquote")); } @@ -349,7 +247,7 @@ nsHTMLEditUtils::IsBlockquote(nsIDOMNode *node) PRBool nsHTMLEditUtils::IsPre(nsIDOMNode *node) { - return NodeIsType(node, NS_LITERAL_STRING("pre")); + return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("pre")); } @@ -359,7 +257,7 @@ nsHTMLEditUtils::IsPre(nsIDOMNode *node) PRBool nsHTMLEditUtils::IsAddress(nsIDOMNode *node) { - return NodeIsType(node, NS_LITERAL_STRING("address")); + return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("address")); } @@ -369,7 +267,7 @@ nsHTMLEditUtils::IsAddress(nsIDOMNode *node) PRBool nsHTMLEditUtils::IsAnchor(nsIDOMNode *node) { - return NodeIsType(node, NS_LITERAL_STRING("a")); + return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("a")); } @@ -379,7 +277,7 @@ nsHTMLEditUtils::IsAnchor(nsIDOMNode *node) PRBool nsHTMLEditUtils::IsImage(nsIDOMNode *node) { - return NodeIsType(node, NS_LITERAL_STRING("img")); + return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("img")); } PRBool @@ -417,7 +315,7 @@ nsHTMLEditUtils::IsNamedAnchor(nsIDOMNode *aNode) PRBool nsHTMLEditUtils::IsDiv(nsIDOMNode *node) { - return NodeIsType(node, NS_LITERAL_STRING("div")); + return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("div")); } @@ -427,7 +325,7 @@ nsHTMLEditUtils::IsDiv(nsIDOMNode *node) PRBool nsHTMLEditUtils::IsNormalDiv(nsIDOMNode *node) { - if (IsDiv(node) && !nsHTMLEditUtils::HasMozAttr(node)) return PR_TRUE; + if (IsDiv(node) && !nsTextEditUtils::HasMozAttr(node)) return PR_TRUE; return PR_FALSE; } @@ -438,7 +336,7 @@ nsHTMLEditUtils::IsNormalDiv(nsIDOMNode *node) PRBool nsHTMLEditUtils::IsMozDiv(nsIDOMNode *node) { - if (IsDiv(node) && HasMozAttr(node)) return PR_TRUE; + if (IsDiv(node) && nsTextEditUtils::HasMozAttr(node)) return PR_TRUE; return PR_FALSE; } @@ -474,7 +372,7 @@ nsHTMLEditUtils::IsMailCite(nsIDOMNode *node) PRBool nsHTMLEditUtils::IsTextarea(nsIDOMNode *node) { - return NodeIsType(node, NS_LITERAL_STRING("textarea")); + return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("textarea")); } @@ -484,7 +382,7 @@ nsHTMLEditUtils::IsTextarea(nsIDOMNode *node) PRBool nsHTMLEditUtils::IsMap(nsIDOMNode *node) { - return NodeIsType(node, NS_LITERAL_STRING("map")); + return nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("map")); } diff --git a/mozilla/editor/libeditor/html/nsHTMLEditUtils.h b/mozilla/editor/libeditor/html/nsHTMLEditUtils.h index f7ed2f0b58e..e644c7d72ed 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditUtils.h +++ b/mozilla/editor/libeditor/html/nsHTMLEditUtils.h @@ -25,23 +25,15 @@ #include "prtypes.h" // for PRBool #include "nsError.h" // for nsresult -#include "nsString.h" // for nsAReadableString class nsIEditor; class nsIDOMNode; class nsHTMLEditUtils { public: - static PRBool NodeIsType(nsIDOMNode *aNode, const nsAReadableString& aTag); - // from nsTextEditRules: - static PRBool IsBody(nsIDOMNode *aNode); - static PRBool IsBreak(nsIDOMNode *aNode); static PRBool IsBig(nsIDOMNode *aNode); static PRBool IsSmall(nsIDOMNode *aNode); - static PRBool IsMozBR(nsIDOMNode *aNode); - static PRBool HasMozAttr(nsIDOMNode *aNode); - static PRBool InBody(nsIDOMNode *aNode, nsIEditor *aEditor); // from nsHTMLEditRules: static PRBool IsHeader(nsIDOMNode *aNode); diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp index 0f41f4aeadf..b9c5d507ec5 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp @@ -25,9 +25,11 @@ #include "nsHTMLEditor.h" #include "nsHTMLEditRules.h" +#include "nsTextEditUtils.h" #include "nsHTMLEditUtils.h" #include "nsEditorEventListeners.h" +#include "TypeInState.h" #include "nsIDOMText.h" #include "nsIDOMNodeList.h" @@ -45,6 +47,8 @@ #include "nsIDOMHTMLImageElement.h" #include "nsISelectionController.h" +#include "TransactionFactory.h" + #include "nsIIndependentSelection.h" //domselections answer to frameselection #include "nsICSSLoader.h" @@ -74,13 +78,12 @@ #include "nsIDOMDocumentFragment.h" #include "nsIPresShell.h" #include "nsIPresContext.h" -#include "nsIParser.h" #include "nsParserCIID.h" +#include "nsIParserService.h" #include "nsIImage.h" #include "nsAOLCiter.h" #include "nsInternetCiter.h" #include "nsISupportsPrimitives.h" -#include "InsertTextTxn.h" #include "SetDocTitleTxn.h" // netwerk @@ -95,7 +98,6 @@ #include "nsIDOMNSUIEvent.h" // Transactionas -#include "PlaceholderTxn.h" #include "nsStyleSheetTxns.h" // Misc @@ -103,8 +105,6 @@ #include "nsEditorUtils.h" #include "nsIPref.h" -const PRUnichar nbsp = 160; - // HACK - CID for NS_CTRANSITIONAL_DTD_CID so that we can get at transitional dtd #define NS_CTRANSITIONAL_DTD_CID \ { 0x4611d482, 0x960a, 0x11d4, { 0x8e, 0xb0, 0xb6, 0x17, 0x66, 0x1b, 0x6f, 0x7c } } @@ -116,8 +116,7 @@ static NS_DEFINE_IID(kSubtreeIteratorCID, NS_SUBTREEITERATOR_CID); static NS_DEFINE_CID(kCRangeCID, NS_RANGE_CID); static NS_DEFINE_CID(kCDOMSelectionCID, NS_DOMSELECTION_CID); static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID); -static NS_DEFINE_IID(kCParserIID, NS_IPARSER_IID); -static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID); +static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID); static NS_DEFINE_CID(kCTransitionalDTDCID, NS_CTRANSITIONAL_DTD_CID); #if defined(NS_DEBUG) && defined(DEBUG_buster) @@ -232,7 +231,12 @@ NS_IMETHODIMP nsHTMLEditor::Init(nsIDOMDocument *aDoc, return NS_ERROR_NULL_POINTER; nsresult result = NS_OK, rulesRes = NS_OK; - + + // Init mEditProperty + result = NS_NewEditProperty(getter_AddRefs(mEditProperty)); + if (NS_FAILED(result)) { return result; } + if (!mEditProperty) {return NS_ERROR_NULL_POINTER;} + if (1) { // block to scope nsAutoEditInitRulesTrigger @@ -416,6 +420,117 @@ NS_IMETHODIMP nsHTMLEditor::InitRules() return res; } +/** + * Returns true if the id represents an element of block type. + * Can be used to determine if a new paragraph should be started. + */ +nsresult +nsHTMLEditor::NodeIsBlockStatic(nsIDOMNode *aNode, PRBool &aIsBlock) +{ + if (!aNode) { return NS_ERROR_NULL_POINTER; } + + nsresult rv; + + nsCOMPtr<nsIDOMElement>element; + element = do_QueryInterface(aNode); + if (!element) + { + // We don't have an element -- probably a text node + aIsBlock = PR_FALSE; + return NS_OK; + } + + aIsBlock = PR_FALSE; + + // Get the node name and atom: + nsAutoString tagName; + rv = element->GetTagName(tagName); + if (NS_FAILED(rv)) return rv; + + tagName.ToLowerCase(); + nsCOMPtr<nsIAtom> tagAtom = NS_NewAtom(tagName); + if (!tagAtom) return NS_ERROR_NULL_POINTER; + + static nsCOMPtr<nsIParserService> sParserService; + if (!sParserService) { + sParserService = do_GetService(kParserServiceCID, &rv); + if (NS_FAILED(rv)) return rv; + } + + // Nodes we know we want to treat as block + // even though the parser says they're not: + if (tagAtom==nsIEditProperty::body || + tagAtom==nsIEditProperty::tbody || + tagAtom==nsIEditProperty::thead || + tagAtom==nsIEditProperty::tfoot || + tagAtom==nsIEditProperty::tr || + tagAtom==nsIEditProperty::th || + tagAtom==nsIEditProperty::td || + tagAtom==nsIEditProperty::pre) + { + aIsBlock = PR_TRUE; + return NS_OK; + } + + // This sucks. The parser service's isBlock requires a string, + // so we have to get the name atom, convert it into a string, call + // the parser service to get the id, in order to call the parser + // service to ask about blockness. + // Harish is working on a more efficient API we can use. + PRInt32 id; + rv = sParserService->HTMLStringTagToId(tagName, &id); + if (NS_FAILED(rv)) return rv; + rv = sParserService->IsBlock(id, aIsBlock); + +#ifdef DEBUG + // Check this against what we would have said with the old code: + if (tagAtom==nsIEditProperty::p || + tagAtom==nsIEditProperty::div || + tagAtom==nsIEditProperty::blockquote || + tagAtom==nsIEditProperty::h1 || + tagAtom==nsIEditProperty::h2 || + tagAtom==nsIEditProperty::h3 || + tagAtom==nsIEditProperty::h4 || + tagAtom==nsIEditProperty::h5 || + tagAtom==nsIEditProperty::h6 || + tagAtom==nsIEditProperty::ul || + tagAtom==nsIEditProperty::ol || + tagAtom==nsIEditProperty::dl || + tagAtom==nsIEditProperty::noscript || + tagAtom==nsIEditProperty::form || + tagAtom==nsIEditProperty::hr || + tagAtom==nsIEditProperty::table || + tagAtom==nsIEditProperty::fieldset || + tagAtom==nsIEditProperty::address || + tagAtom==nsIEditProperty::caption || + tagAtom==nsIEditProperty::col || + tagAtom==nsIEditProperty::colgroup || + tagAtom==nsIEditProperty::li || + tagAtom==nsIEditProperty::dt || + tagAtom==nsIEditProperty::dd || + tagAtom==nsIEditProperty::legend ) + { + if (!aIsBlock) + { + nsAutoString assertmsg (NS_LITERAL_STRING("Parser and editor disagree on blockness: ")); + assertmsg.Append(tagName); + char* assertstr = assertmsg.ToNewCString(); + NS_ASSERTION(aIsBlock, assertstr); + Recycle(assertstr); + } + } +#endif /* DEBUG */ + + return rv; +} + +// Non-static version for the nsIEditor interface and JavaScript +NS_IMETHODIMP +nsHTMLEditor::NodeIsBlock(nsIDOMNode *aNode, PRBool &aIsBlock) +{ + return NodeIsBlockStatic(aNode, aIsBlock); +} + NS_IMETHODIMP nsHTMLEditor::SetDocumentTitle(const PRUnichar *aTitle) { @@ -436,6 +551,427 @@ nsHTMLEditor::SetDocumentTitle(const PRUnichar *aTitle) return result; } +/* ------------ Block methods moved from nsEditor -------------- */ +/////////////////////////////////////////////////////////////////////////// +// GetBlockNodeParent: returns enclosing block level ancestor, if any +// +nsCOMPtr<nsIDOMNode> +nsHTMLEditor::GetBlockNodeParent(nsIDOMNode *aNode) +{ + nsCOMPtr<nsIDOMNode> tmp; + nsCOMPtr<nsIDOMNode> p; + + if (!aNode) + { + NS_NOTREACHED("null node passed to GetBlockNodeParent()"); + return PR_FALSE; + } + + if (NS_FAILED(aNode->GetParentNode(getter_AddRefs(p)))) // no parent, ran off top of tree + return tmp; + + while (p) + { + PRBool isBlock; + if (NS_FAILED(NodeIsBlockStatic(p, isBlock)) || isBlock) + break; + if ( NS_FAILED(p->GetParentNode(getter_AddRefs(tmp))) || !tmp) // no parent, ran off top of tree + return p; + + p = tmp; + } + return p; +} + + +/////////////////////////////////////////////////////////////////////////// +// HasSameBlockNodeParent: true if nodes have same block level ancestor +// +PRBool +nsHTMLEditor::HasSameBlockNodeParent(nsIDOMNode *aNode1, nsIDOMNode *aNode2) +{ + if (!aNode1 || !aNode2) + { + NS_NOTREACHED("null node passed to HasSameBlockNodeParent()"); + return PR_FALSE; + } + + if (aNode1 == aNode2) + return PR_TRUE; + + nsCOMPtr<nsIDOMNode> p1 = GetBlockNodeParent(aNode1); + nsCOMPtr<nsIDOMNode> p2 = GetBlockNodeParent(aNode2); + + return (p1 == p2); +} + + +/////////////////////////////////////////////////////////////////////////// +// GetBlockSection: return leftmost/rightmost nodes in aChild's block +// +nsresult +nsHTMLEditor::GetBlockSection(nsIDOMNode *aChild, + nsIDOMNode **aLeftNode, + nsIDOMNode **aRightNode) +{ + nsresult result = NS_OK; + if (!aChild || !aLeftNode || !aRightNode) {return NS_ERROR_NULL_POINTER;} + *aLeftNode = aChild; + *aRightNode = aChild; + + nsCOMPtr<nsIDOMNode>sibling; + result = aChild->GetPreviousSibling(getter_AddRefs(sibling)); + while ((NS_SUCCEEDED(result)) && sibling) + { + PRBool isBlock; + NodeIsBlockStatic(sibling, isBlock); + if (isBlock) + { + nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling); + if (!nodeAsText) { + break; + } + // XXX: needs some logic to work for other leaf nodes besides text! + } + *aLeftNode = sibling; + result = (*aLeftNode)->GetPreviousSibling(getter_AddRefs(sibling)); + } + NS_ADDREF((*aLeftNode)); + // now do the right side + result = aChild->GetNextSibling(getter_AddRefs(sibling)); + while ((NS_SUCCEEDED(result)) && sibling) + { + PRBool isBlock; + NodeIsBlockStatic(sibling, isBlock); + if (isBlock) + { + nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling); + if (!nodeAsText) { + break; + } + } + *aRightNode = sibling; + result = (*aRightNode)->GetNextSibling(getter_AddRefs(sibling)); + } + NS_ADDREF((*aRightNode)); + if (gNoisy) { printf("GetBlockSection returning %p %p\n", + (void*)(*aLeftNode), (void*)(*aRightNode)); } + + return result; +} + + +/////////////////////////////////////////////////////////////////////////// +// GetBlockSectionsForRange: return list of block sections that intersect +// this range +nsresult +nsHTMLEditor::GetBlockSectionsForRange(nsIDOMRange *aRange, + nsISupportsArray *aSections) +{ + if (!aRange || !aSections) {return NS_ERROR_NULL_POINTER;} + + nsresult result; + nsCOMPtr<nsIContentIterator>iter; + result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull, + NS_GET_IID(nsIContentIterator), getter_AddRefs(iter)); + if ((NS_SUCCEEDED(result)) && iter) + { + nsCOMPtr<nsIDOMRange> lastRange; + iter->Init(aRange); + nsCOMPtr<nsIContent> currentContent; + iter->CurrentNode(getter_AddRefs(currentContent)); + while (NS_ENUMERATOR_FALSE == iter->IsDone()) + { + nsCOMPtr<nsIDOMNode>currentNode = do_QueryInterface(currentContent); + if (currentNode) + { + nsCOMPtr<nsIAtom> currentContentTag; + currentContent->GetTag(*getter_AddRefs(currentContentTag)); + // <BR> divides block content ranges. We can achieve this by nulling out lastRange + if (nsIEditProperty::br==currentContentTag.get()) + { + lastRange = do_QueryInterface(nsnull); + } + else + { + PRBool isNotInlineOrText; + result = NodeIsBlockStatic(currentNode, isNotInlineOrText); + if (isNotInlineOrText) + { + PRUint16 nodeType; + currentNode->GetNodeType(&nodeType); + if (nsIDOMNode::TEXT_NODE == nodeType) { + isNotInlineOrText = PR_TRUE; + } + } + if (PR_FALSE==isNotInlineOrText) + { + nsCOMPtr<nsIDOMNode>leftNode; + nsCOMPtr<nsIDOMNode>rightNode; + result = GetBlockSection(currentNode, + getter_AddRefs(leftNode), + getter_AddRefs(rightNode)); + if (gNoisy) {printf("currentNode %p has block content (%p,%p)\n", (void*)currentNode.get(), (void*)leftNode.get(), (void*)rightNode.get());} + if ((NS_SUCCEEDED(result)) && leftNode && rightNode) + { + // add range to the list if it doesn't overlap with the previous range + PRBool addRange=PR_TRUE; + if (lastRange) + { + nsCOMPtr<nsIDOMNode> lastStartNode; + nsCOMPtr<nsIDOMElement> blockParentOfLastStartNode; + lastRange->GetStartContainer(getter_AddRefs(lastStartNode)); + blockParentOfLastStartNode = do_QueryInterface(GetBlockNodeParent(lastStartNode)); + if (blockParentOfLastStartNode) + { + if (gNoisy) {printf("lastStartNode %p has block parent %p\n", (void*)lastStartNode.get(), (void*)blockParentOfLastStartNode.get());} + nsCOMPtr<nsIDOMElement> blockParentOfLeftNode; + blockParentOfLeftNode = do_QueryInterface(GetBlockNodeParent(leftNode)); + if (blockParentOfLeftNode) + { + if (gNoisy) {printf("leftNode %p has block parent %p\n", (void*)leftNode.get(), (void*)blockParentOfLeftNode.get());} + if (blockParentOfLastStartNode==blockParentOfLeftNode) { + addRange = PR_FALSE; + } + } + } + } + if (PR_TRUE==addRange) + { + if (gNoisy) {printf("adding range, setting lastRange with start node %p\n", (void*)leftNode.get());} + nsCOMPtr<nsIDOMRange> range; + result = nsComponentManager::CreateInstance(kCRangeCID, nsnull, + NS_GET_IID(nsIDOMRange), 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; +} + + +/////////////////////////////////////////////////////////////////////////// +// NextNodeInBlock: gets the next/prev node in the block, if any. Next node +// must be an element or text node, others are ignored +nsCOMPtr<nsIDOMNode> +nsHTMLEditor::NextNodeInBlock(nsIDOMNode *aNode, IterDirection aDir) +{ + nsCOMPtr<nsIDOMNode> nullNode; + nsCOMPtr<nsIContent> content; + nsCOMPtr<nsIContent> blockContent; + nsCOMPtr<nsIDOMNode> node; + nsCOMPtr<nsIDOMNode> blockParent; + + if (!aNode) return nullNode; + + nsCOMPtr<nsIContentIterator> iter; + if (NS_FAILED(nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull, + NS_GET_IID(nsIContentIterator), + getter_AddRefs(iter)))) + return nullNode; + + // much gnashing of teeth as we twit back and forth between content and domnode types + content = do_QueryInterface(aNode); + PRBool isBlock; + if (NS_SUCCEEDED(NodeIsBlockStatic(aNode, isBlock)) && isBlock) + { + blockParent = do_QueryInterface(aNode); + } + else + { + blockParent = GetBlockNodeParent(aNode); + } + if (!blockParent) return nullNode; + blockContent = do_QueryInterface(blockParent); + if (!blockContent) return nullNode; + + if (NS_FAILED(iter->Init(blockContent))) return nullNode; + if (NS_FAILED(iter->PositionAt(content))) return nullNode; + + while (NS_ENUMERATOR_FALSE == iter->IsDone()) + { + if (NS_FAILED(iter->CurrentNode(getter_AddRefs(content)))) return nullNode; + // ignore nodes that aren't elements or text, or that are the block parent + node = do_QueryInterface(content); + if (node && IsTextOrElementNode(node) && (node != blockParent) && (node.get() != aNode)) + return node; + + if (aDir == kIterForward) + iter->Next(); + else + iter->Prev(); + } + + return nullNode; +} + +static const PRUnichar nbsp = 160; + +/////////////////////////////////////////////////////////////////////////// +// IsNextCharWhitespace: checks the adjacent content in the same block +// to see if following selection is whitespace or nbsp +nsresult +nsHTMLEditor::IsNextCharWhitespace(nsIDOMNode *aParentNode, + PRInt32 aOffset, + PRBool *outIsSpace, + PRBool *outIsNBSP, + nsCOMPtr<nsIDOMNode> *outNode, + PRInt32 *outOffset) +{ + if (!outIsSpace || !outIsNBSP) return NS_ERROR_NULL_POINTER; + *outIsSpace = PR_FALSE; + *outIsNBSP = PR_FALSE; + if (outNode) *outNode = nsnull; + if (outOffset) *outOffset = -1; + + nsAutoString tempString; + PRUint32 strLength; + nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(aParentNode); + if (textNode) + { + textNode->GetLength(&strLength); + if ((PRUint32)aOffset < strLength) + { + // easy case: next char is in same node + textNode->SubstringData(aOffset,aOffset+1,tempString); + *outIsSpace = nsCRT::IsAsciiSpace(tempString.First()); + *outIsNBSP = (tempString.First() == nbsp); + if (outNode) *outNode = do_QueryInterface(aParentNode); + if (outOffset) *outOffset = aOffset+1; // yes, this is _past_ the character; + return NS_OK; + } + } + + // harder case: next char in next node. + nsCOMPtr<nsIDOMNode> node = NextNodeInBlock(aParentNode, kIterForward); + nsCOMPtr<nsIDOMNode> tmp; + while (node) + { + PRBool isBlock (PR_FALSE); + NodeIsBlock(node, isBlock); + if (isBlock) // skip over bold, italic, link, ect nodes + { + if (IsTextNode(node) && IsEditable(node)) + { + textNode = do_QueryInterface(node); + textNode->GetLength(&strLength); + if (strLength) + { + textNode->SubstringData(0,1,tempString); + *outIsSpace = nsCRT::IsAsciiSpace(tempString.First()); + *outIsNBSP = (tempString.First() == nbsp); + if (outNode) *outNode = do_QueryInterface(node); + if (outOffset) *outOffset = 1; // yes, this is _past_ the character; + return NS_OK; + } + // else it's an empty text node, or not editable; skip it. + } + else // node is an image or some other thingy that doesn't count as whitespace + { + break; + } + } + tmp = node; + node = NextNodeInBlock(tmp, kIterForward); + } + + return NS_OK; +} + + +/////////////////////////////////////////////////////////////////////////// +// IsPrevCharWhitespace: checks the adjacent content in the same block +// to see if following selection is whitespace +nsresult +nsHTMLEditor::IsPrevCharWhitespace(nsIDOMNode *aParentNode, + PRInt32 aOffset, + PRBool *outIsSpace, + PRBool *outIsNBSP, + nsCOMPtr<nsIDOMNode> *outNode, + PRInt32 *outOffset) +{ + if (!outIsSpace || !outIsNBSP) return NS_ERROR_NULL_POINTER; + *outIsSpace = PR_FALSE; + *outIsNBSP = PR_FALSE; + if (outNode) *outNode = nsnull; + if (outOffset) *outOffset = -1; + + nsAutoString tempString; + PRUint32 strLength; + nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(aParentNode); + if (textNode) + { + if (aOffset > 0) + { + // easy case: prev char is in same node + textNode->SubstringData(aOffset-1,aOffset,tempString); + *outIsSpace = nsCRT::IsAsciiSpace(tempString.First()); + *outIsNBSP = (tempString.First() == nbsp); + if (outNode) *outNode = do_QueryInterface(aParentNode); + if (outOffset) *outOffset = aOffset-1; + return NS_OK; + } + } + + // harder case: prev char in next node + nsCOMPtr<nsIDOMNode> node = NextNodeInBlock(aParentNode, kIterBackward); + nsCOMPtr<nsIDOMNode> tmp; + while (node) + { + PRBool isBlock (PR_FALSE); + NodeIsBlock(node, isBlock); + if (isBlock) // skip over bold, italic, link, ect nodes + { + if (IsTextNode(node) && IsEditable(node)) + { + textNode = do_QueryInterface(node); + textNode->GetLength(&strLength); + if (strLength) + { + // you could use nsITextContent::IsOnlyWhitespace here + textNode->SubstringData(strLength-1,strLength,tempString); + *outIsSpace = nsCRT::IsAsciiSpace(tempString.First()); + *outIsNBSP = (tempString.First() == nbsp); + if (outNode) *outNode = do_QueryInterface(aParentNode); + if (outOffset) *outOffset = strLength-1; + return NS_OK; + } + // else it's an empty text node, or not editable; skip it. + } + else // node is an image or some other thingy that doesn't count as whitespace + { + break; + } + } + // otherwise we found a node we want to skip, keep going + tmp = node; + node = NextNodeInBlock(tmp, kIterBackward); + } + + return NS_OK; + +} + + + +/* ------------ End Block methods -------------- */ + + PRBool nsHTMLEditor::IsModifiable() { PRUint32 flags; @@ -482,8 +1018,10 @@ NS_IMETHODIMP nsHTMLEditor::HandleKeyPress(nsIDOMKeyEvent* aKeyEvent) res = GetStartNodeAndOffset(selection, address_of(node), &offset); if (NS_FAILED(res)) return res; if (!node) return NS_ERROR_FAILURE; - - if (IsBlockNode(node)) blockParent = node; + + PRBool isBlock (PR_FALSE); + NodeIsBlock(node, isBlock); + if (isBlock) blockParent = node; else blockParent = GetBlockNodeParent(node); if (blockParent) @@ -1171,7 +1709,7 @@ nsHTMLEditor::InsertNodeAtPoint(nsIDOMNode *aNode, { // If the current parent is a root (body or table element) // then go no further - we can't insert - if (nsHTMLEditUtils::IsBody(parent) || nsHTMLEditUtils::IsTableElement(parent)) + if (nsTextEditUtils::IsBody(parent) || nsHTMLEditUtils::IsTableElement(parent)) return NS_ERROR_FAILURE; // Get the next parent parent->GetParentNode(getter_AddRefs(tmp)); @@ -1311,7 +1849,9 @@ nsHTMLEditor::GetParentBlockTags(nsStringArray *aTagList, PRBool aGetLists) } else { - if (IsBlockNode(node)) blockParent = node; + PRBool isBlock (PR_FALSE); + NodeIsBlock(node, isBlock); + if (isBlock) blockParent = node; else blockParent = GetBlockNodeParent(node); blockParentElem = do_QueryInterface(blockParent); } @@ -1427,7 +1967,7 @@ nsHTMLEditor::GetBackgroundColorState(PRBool &aMixed, nsString &aOutColor) return NS_OK; // Once we hit the body, we're done - if(nsHTMLEditUtils::IsBody(element)) return NS_OK; + if(nsTextEditUtils::IsBody(element)) return NS_OK; // No color is set, but we need to report visible color inherited // from nested cells/tables, so search up parent chain @@ -2878,7 +3418,6 @@ nsHTMLEditor::EndOperation() return res; } - PRBool nsHTMLEditor::TagCanContainTag(const nsString &aParentTag, const nsString &aChildTag) { @@ -3090,7 +3629,7 @@ void nsHTMLEditor::IsTextStyleSet(nsIStyleContext *aSC, PRBool nsHTMLEditor::IsElementInBody(nsIDOMElement* aElement) { - return nsHTMLEditUtils::InBody(aElement, this); + return nsTextEditUtils::InBody(aElement, this); } PRBool @@ -3534,7 +4073,7 @@ nsHTMLEditor::GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode if (NS_FAILED(res)) return res; // if it's not in the body, then zero it out - if (*outNode && !nsHTMLEditUtils::InBody(*outNode, this)) + if (*outNode && !nsTextEditUtils::InBody(*outNode, this)) { *outNode = nsnull; } @@ -3553,7 +4092,7 @@ nsHTMLEditor::GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr< if (NS_FAILED(res)) return res; // if it's not in the body, then zero it out - if (*outNode && !nsHTMLEditUtils::InBody(*outNode, this)) + if (*outNode && !nsTextEditUtils::InBody(*outNode, this)) { *outNode = nsnull; } @@ -3573,7 +4112,7 @@ nsHTMLEditor::GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode) if (NS_FAILED(res)) return res; // if it's not in the body, then zero it out - if (*outNode && !nsHTMLEditUtils::InBody(*outNode, this)) + if (*outNode && !nsTextEditUtils::InBody(*outNode, this)) { *outNode = nsnull; } @@ -3592,7 +4131,7 @@ nsHTMLEditor::GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<n if (NS_FAILED(res)) return res; // if it's not in the body, then zero it out - if (*outNode && !nsHTMLEditUtils::InBody(*outNode, this)) + if (*outNode && !nsTextEditUtils::InBody(*outNode, this)) { *outNode = nsnull; } @@ -3872,7 +4411,7 @@ nsHTMLEditor::IsEmptyNode( nsIDOMNode *aNode, // is it the node we are iterating over? if (node.get() == aNode) break; // is it a moz-BR and did the caller ask us not to consider those relevant? - if (!(aMozBRDoesntCount && nsHTMLEditUtils::IsMozBR(node))) + if (!(aMozBRDoesntCount && nsTextEditUtils::IsMozBR(node))) { // is it an empty node of some sort? PRBool isEmptyNode; diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.h b/mozilla/editor/libeditor/html/nsHTMLEditor.h index 519eb5193a5..481ccf5ee83 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.h +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.h @@ -39,14 +39,16 @@ #include "nsICSSLoaderObserver.h" #include "nsITableLayout.h" -#include "TypeInState.h" #include "nsEditRules.h" + +#include "nsIEditProperty.h" class nsIDOMKeyEvent; class nsITransferable; class nsIDOMEventReceiver; class nsIDOMNSRange; class nsIDocumentEncoder; +class TypeInState; /** * The HTML editor implementation.<br> @@ -54,7 +56,6 @@ class nsIDocumentEncoder; */ class nsHTMLEditor : public nsPlaintextEditor, public nsIHTMLEditor, - public nsIEditorMailSupport, public nsITableEditor, public nsIEditorStyleSheets, public nsICSSLoaderObserver @@ -244,11 +245,67 @@ public: // aTitle may be null or empty string to remove child contents of <title> NS_IMETHOD SetDocumentTitle(const PRUnichar *aTitle); + /* ------------ Block methods moved from nsEditor -------------- */ + static nsCOMPtr<nsIDOMNode> GetBlockNodeParent(nsIDOMNode *aNode); + static PRBool HasSameBlockNodeParent(nsIDOMNode *aNode1, nsIDOMNode *aNode2); + /** Determines the bounding nodes for the block section containing aNode. + * The calculation is based on some nodes intrinsically being block elements + * acording to HTML. Style sheets are not considered in this calculation. + * <BR> tags separate block content sections. So the HTML markup: + * <PRE> + * <P>text1<BR>text2<B>text3</B></P> + * </PRE> + * contains two block content sections. The first has the text node "text1" + * for both endpoints. The second has "text2" as the left endpoint and + * "text3" as the right endpoint. + * Notice that offsets aren't required, only leaf nodes. Offsets are implicit. + * + * @param aNode the block content returned includes aNode + * @param aLeftNode [OUT] the left endpoint of the block content containing aNode + * @param aRightNode [OUT] the right endpoint of the block content containing aNode + * + */ + static nsresult GetBlockSection(nsIDOMNode *aNode, + nsIDOMNode **aLeftNode, + nsIDOMNode **aRightNode); + + /** Compute the set of block sections in a given range. + * A block section is the set of (leftNode, rightNode) pairs given + * by GetBlockSection. The set is computed by computing the + * block section for every leaf node in the range and throwing + * out duplicates. + * + * @param aRange The range to compute block sections for. + * @param aSections Allocated storage for the resulting set, stored as nsIDOMRanges. + */ + static nsresult GetBlockSectionsForRange(nsIDOMRange *aRange, + nsISupportsArray *aSections); + + static nsCOMPtr<nsIDOMNode> NextNodeInBlock(nsIDOMNode *aNode, IterDirection aDir); + nsresult IsNextCharWhitespace(nsIDOMNode *aParentNode, + PRInt32 aOffset, + PRBool *outIsSpace, + PRBool *outIsNBSP, + nsCOMPtr<nsIDOMNode> *outNode = 0, + PRInt32 *outOffset = 0); + nsresult IsPrevCharWhitespace(nsIDOMNode *aParentNode, + PRInt32 aOffset, + PRBool *outIsSpace, + PRBool *outIsNBSP, + nsCOMPtr<nsIDOMNode> *outNode = 0, + PRInt32 *outOffset = 0); + /* ------------ Overrides of nsEditor interface methods -------------- */ /** prepare the editor for use */ NS_IMETHOD Init(nsIDOMDocument *aDoc, nsIPresShell *aPresShell, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags); + /** Internal, static version */ + static nsresult NodeIsBlockStatic(nsIDOMNode *aNode, PRBool &aIsBlock); + + /** This version is for exposure to JavaScript */ + NS_IMETHOD NodeIsBlock(nsIDOMNode *aNode, PRBool &aIsBlock); + /** we override this here to install event listeners */ NS_IMETHOD PostCreate(); @@ -595,6 +652,9 @@ protected: nsCOMPtr<nsIAtom> mUnderlineAtom; nsCOMPtr<nsIAtom> mFontAtom; nsCOMPtr<nsIAtom> mLinkAtom; + + nsCOMPtr<nsIEditProperty> mEditProperty; + nsCOMPtr<nsIDOMNode> mCachedNode; PRBool mCachedBoldStyle; diff --git a/mozilla/editor/libeditor/html/nsHTMLEditorStyle.cpp b/mozilla/editor/libeditor/html/nsHTMLEditorStyle.cpp index 8e034d050ee..b17f5ff0e1b 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditorStyle.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditorStyle.cpp @@ -22,6 +22,7 @@ #include "nsHTMLEditor.h" #include "nsHTMLEditRules.h" +#include "nsTextEditUtils.h" #include "nsHTMLEditUtils.h" #include "nsEditorEventListeners.h" @@ -50,6 +51,7 @@ #include "nsIDocumentStateListener.h" #include "nsIStyleContext.h" +#include "TypeInState.h" #include "nsIEnumerator.h" #include "nsIContent.h" @@ -482,7 +484,7 @@ nsresult nsHTMLEditor::SplitStyleAbovePoint(nsCOMPtr<nsIDOMNode> *aNode, // split any matching style nodes above the node/offset nsCOMPtr<nsIDOMNode> parent, tmp = *aNode; PRInt32 offset; - while (tmp && !nsHTMLEditUtils::IsBody(tmp)) + while (tmp && !nsTextEditUtils::IsBody(tmp)) { if ( (aProperty && NodeIsType(tmp, aProperty)) || // node is the correct inline prop (aProperty == nsIEditProperty::href && nsHTMLEditUtils::IsLink(tmp)) || // node is href - test if really <a href=... @@ -505,7 +507,9 @@ PRBool nsHTMLEditor::NodeIsProperty(nsIDOMNode *aNode) if (!aNode) return PR_FALSE; if (!IsContainer(aNode)) return PR_FALSE; if (!IsEditable(aNode)) return PR_FALSE; - if (!IsInlineNode(aNode)) return PR_FALSE; + PRBool isBlock (PR_FALSE); + NodeIsBlock(aNode, isBlock); + if (isBlock) return PR_FALSE; if (NodeIsType(aNode, nsIEditProperty::a)) return PR_FALSE; return PR_TRUE; } @@ -718,7 +722,7 @@ nsresult nsHTMLEditor::PromoteInlineRange(nsIDOMRange *inRange) if (NS_FAILED(res)) return res; while ( startNode && - !nsHTMLEditUtils::IsBody(startNode) && + !nsTextEditUtils::IsBody(startNode) && IsAtFrontOfNode(startNode, startOffset) ) { res = GetNodeLocation(startNode, address_of(parent), &startOffset); @@ -728,7 +732,7 @@ nsresult nsHTMLEditor::PromoteInlineRange(nsIDOMRange *inRange) if (!startNode) return NS_ERROR_NULL_POINTER; while ( endNode && - !nsHTMLEditUtils::IsBody(endNode) && + !nsTextEditUtils::IsBody(endNode) && IsAtEndOfNode(endNode, endOffset) ) { res = GetNodeLocation(endNode, address_of(parent), &endOffset); diff --git a/mozilla/editor/libeditor/html/nsTableEditor.cpp b/mozilla/editor/libeditor/html/nsTableEditor.cpp index 694e88e3f66..426d1bfe361 100644 --- a/mozilla/editor/libeditor/html/nsTableEditor.cpp +++ b/mozilla/editor/libeditor/html/nsTableEditor.cpp @@ -45,6 +45,7 @@ #include "nsVoidArray.h" #include "nsEditorUtils.h" +#include "nsTextEditUtils.h" #include "nsHTMLEditUtils.h" static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID); @@ -3534,7 +3535,7 @@ nsHTMLEditor::IsEmptyCell(nsIDOMElement *aCell) { // We insert a single break into a cell by default // to have some place to locate a cursor -- it is dispensable - PRBool isEmpty = nsHTMLEditUtils::IsBreak(cellChild); + PRBool isEmpty = nsTextEditUtils::IsBreak(cellChild); // Or check if no real content if (!isEmpty) IsEmptyNode(cellChild, &isEmpty, PR_FALSE, PR_FALSE); diff --git a/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp b/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp index a318564349f..bc6450b5ac2 100644 --- a/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp +++ b/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp @@ -32,7 +32,6 @@ #include "nsIDOMElement.h" #include "nsISelection.h" #include "nsIDOMCharacterData.h" -#include "nsIEditProperty.h" #include "nsISupportsArray.h" #include "nsIStringStream.h" #include "nsIDOMKeyEvent.h" diff --git a/mozilla/editor/libeditor/text/nsPlaintextDataTransfer.cpp b/mozilla/editor/libeditor/text/nsPlaintextDataTransfer.cpp index 9c2a42f9fb3..227887e6e9b 100644 --- a/mozilla/editor/libeditor/text/nsPlaintextDataTransfer.cpp +++ b/mozilla/editor/libeditor/text/nsPlaintextDataTransfer.cpp @@ -22,9 +22,7 @@ #include "nsPlaintextEditor.h" -#include "nsHTMLEditUtils.h" - -#include "nsEditorEventListeners.h" +#include "nsTextEditUtils.h" #include "nsIDOMText.h" #include "nsIDOMNodeList.h" @@ -45,7 +43,6 @@ #include "nsIFrameSelection.h" // For TABLESELECTION_ defines #include "nsIIndependentSelection.h" //domselections answer to frameselection - #include "nsICSSLoader.h" #include "nsICSSStyleSheet.h" #include "nsIHTMLContentContainer.h" @@ -80,7 +77,6 @@ #include "nsAOLCiter.h" #include "nsInternetCiter.h" #include "nsISupportsPrimitives.h" -#include "InsertTextTxn.h" // netwerk #include "nsIURI.h" @@ -93,12 +89,7 @@ #include "nsIDragService.h" #include "nsIDOMNSUIEvent.h" -// Transactionas -#include "PlaceholderTxn.h" -#include "nsStyleSheetTxns.h" - // Misc -#include "TextEditorTest.h" #include "nsEditorUtils.h" #include "nsIPref.h" const PRUnichar nbsp = 160; diff --git a/mozilla/editor/libeditor/text/nsPlaintextEditor.cpp b/mozilla/editor/libeditor/text/nsPlaintextEditor.cpp index 73429bceb1f..507487a7e7f 100644 --- a/mozilla/editor/libeditor/text/nsPlaintextEditor.cpp +++ b/mozilla/editor/libeditor/text/nsPlaintextEditor.cpp @@ -22,7 +22,7 @@ #include "nsPlaintextEditor.h" #include "nsICaret.h" -#include "nsHTMLEditUtils.h" +#include "nsTextEditUtils.h" #include "nsTextEditRules.h" #include "nsEditorEventListeners.h" #include "nsIEditActionListener.h" @@ -70,22 +70,27 @@ #include "nsParserCIID.h" #include "nsIImage.h" #include "nsISupportsPrimitives.h" -#include "InsertTextTxn.h" // netwerk #include "nsIURI.h" #include "nsNetUtil.h" -// Transactionas -#include "PlaceholderTxn.h" - // Misc -#include "TextEditorTest.h" #include "nsEditorUtils.h" #include "nsIPref.h" #include "nsStyleConsts.h" #include "nsIStyleContext.h" +#include "nsAOLCiter.h" +#include "nsInternetCiter.h" + +// Drag & Drop, Clipboard +//#include "nsWidgetsCID.h" +#include "nsIClipboard.h" +#include "nsITransferable.h" +//#include "nsIDragService.h" +//#include "nsIDOMNSUIEvent.h" + const PRUnichar nbsp = 160; // HACK - CID for NS_CTRANSITIONAL_DTD_CID so that we can get at transitional dtd @@ -103,6 +108,11 @@ static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID); static NS_DEFINE_IID(kCParserIID, NS_IPARSER_IID); static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID); static NS_DEFINE_CID(kCTransitionalDTDCID, NS_CTRANSITIONAL_DTD_CID); +// Drag & Drop, Clipboard Support +static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); +static NS_DEFINE_CID(kCTransferableCID, NS_TRANSFERABLE_CID); +//static NS_DEFINE_CID(kCDragServiceCID, NS_DRAGSERVICE_CID); +//static NS_DEFINE_CID(kCHTMLFormatConverterCID, NS_HTMLFORMATCONVERTER_CID); #if defined(NS_DEBUG) && defined(DEBUG_buster) static PRBool gNoisy = PR_FALSE; @@ -110,10 +120,6 @@ static PRBool gNoisy = PR_FALSE; static const PRBool gNoisy = PR_FALSE; #endif -nsIAtom *nsPlaintextEditor::gTypingTxnName; -nsIAtom *nsPlaintextEditor::gIMETxnName; -nsIAtom *nsPlaintextEditor::gDeleteTxnName; - // prototype for rules creation shortcut nsresult NS_NewTextEditRules(nsIEditRules** aInstancePtrResult); @@ -127,57 +133,10 @@ nsPlaintextEditor::nsPlaintextEditor() { // Done in nsEditor // NS_INIT_REFCNT(); - if (!gTypingTxnName) - gTypingTxnName = NS_NewAtom("Typing"); - else - NS_ADDREF(gTypingTxnName); - if (!gIMETxnName) - gIMETxnName = NS_NewAtom("IME"); - else - NS_ADDREF(gIMETxnName); - if (!gDeleteTxnName) - gDeleteTxnName = NS_NewAtom("Deleting"); - else - NS_ADDREF(gDeleteTxnName); } nsPlaintextEditor::~nsPlaintextEditor() { - /* first, delete the transaction manager if there is one. - this will release any remaining transactions. - this is important because transactions can hold onto the atoms (gTypingTxnName, ...) - and to make the optimization (holding refcounted statics) work correctly, - the editor instance needs to hold the last refcount. - If you get this wrong, expect to deref a garbage gTypingTxnName pointer if you bring up a second editor. - */ - if (mTxnMgr) { - mTxnMgr = 0; - } - nsrefcnt refCount=0; - if (gTypingTxnName) // we addref'd in the constructor - { // want to release it without nulling out the pointer. - refCount = gTypingTxnName->Release(); - if (0==refCount) { - gTypingTxnName = nsnull; - } - } - - if (gIMETxnName) // we addref'd in the constructor - { // want to release it without nulling out the pointer. - refCount = gIMETxnName->Release(); - if (0==refCount) { - gIMETxnName = nsnull; - } - } - - if (gDeleteTxnName) // we addref'd in the constructor - { // want to release it without nulling out the pointer. - refCount = gDeleteTxnName->Release(); - if (0==refCount) { - gDeleteTxnName = nsnull; - } - } - // remove the rules as an action listener. Else we get a bad ownership loop later on. // it's ok if the rules aren't a listener; we ignore the error. nsCOMPtr<nsIEditActionListener> mListener = do_QueryInterface(mRules); @@ -227,6 +186,16 @@ NS_IMETHODIMP nsPlaintextEditor::QueryInterface(REFNSIID aIID, void** aInstanceP NS_ADDREF_THIS(); return NS_OK; } + if (aIID.Equals(NS_GET_IID(nsIEditor))) { + *aInstancePtr = NS_STATIC_CAST(nsIEditor*, this); + NS_ADDREF_THIS(); + return NS_OK; + } + if (aIID.Equals(NS_GET_IID(nsIEditorMailSupport))) { + *aInstancePtr = NS_STATIC_CAST(nsIEditorMailSupport*, this); + NS_ADDREF_THIS(); + return NS_OK; + } return nsEditor::QueryInterface(aIID, aInstancePtr); } @@ -1436,9 +1405,9 @@ NS_IMETHODIMP nsPlaintextEditor::CanCopy(PRBool &aCanCopy) // Shared between OutputToString and OutputToStream NS_IMETHODIMP nsPlaintextEditor::GetAndInitDocEncoder(const nsAReadableString& aFormatType, - PRUint32 aFlags, - const nsAReadableString* aCharset, - nsIDocumentEncoder** encoder) + PRUint32 aFlags, + const nsAReadableString* aCharset, + nsIDocumentEncoder** encoder) { nsCOMPtr<nsIPresShell> presShell; nsresult rv = GetPresShell(getter_AddRefs(presShell)); @@ -1484,7 +1453,7 @@ nsPlaintextEditor::GetAndInitDocEncoder(const nsAReadableString& aFormatType, nsCOMPtr<nsIDOMElement> rootElement; GetRootElement(getter_AddRefs(rootElement)); NS_ENSURE_TRUE(rootElement, NS_ERROR_FAILURE); - if (!nsHTMLEditUtils::IsBody(rootElement)) + if (!nsTextEditUtils::IsBody(rootElement)) { // XXX Why does this use range rather than selection collapse/extend? nsCOMPtr<nsIDOMRange> range (do_CreateInstance(kCRangeCID, &rv)); @@ -1582,6 +1551,297 @@ nsPlaintextEditor::OutputToStream(nsIOutputStream* aOutputStream, } +#ifdef XP_MAC +#pragma mark - +#pragma mark nsIEditorMailSupport overrides +#pragma mark - +#endif + +NS_IMETHODIMP +nsPlaintextEditor::PasteAsQuotation(PRInt32 aSelectionType) +{ + // Get Clipboard Service + nsresult rv; + NS_WITH_SERVICE(nsIClipboard, clipboard, kCClipboardCID, &rv); + if (NS_FAILED(rv)) return rv; + + // Create generic Transferable for getting the data + nsCOMPtr<nsITransferable> trans; + rv = nsComponentManager::CreateInstance(kCTransferableCID, nsnull, + NS_GET_IID(nsITransferable), + (void**) getter_AddRefs(trans)); + if (NS_SUCCEEDED(rv) && trans) + { + // We only handle plaintext pastes here + trans->AddDataFlavor(kUnicodeMime); + + // Get the Data from the clipboard + clipboard->GetData(trans, aSelectionType); + + // Now we ask the transferable for the data + // it still owns the data, we just have a pointer to it. + // If it can't support a "text" output of the data the call will fail + nsCOMPtr<nsISupports> genericDataObj; + PRUint32 len = 0; + char* flav = 0; + rv = trans->GetAnyTransferData(&flav, getter_AddRefs(genericDataObj), + &len); + if (NS_FAILED(rv)) + { +#ifdef DEBUG_akkana + printf("PasteAsPlaintextQuotation: GetAnyTransferData failed, %d\n", rv); +#endif + return rv; + } +#ifdef DEBUG_clipboard + printf("Got flavor [%s]\n", flav); +#endif + nsAutoString flavor; flavor.AssignWithConversion(flav); + nsAutoString stuffToPaste; + if (flavor.EqualsWithConversion(kUnicodeMime)) + { + nsCOMPtr<nsISupportsWString> textDataObj ( do_QueryInterface(genericDataObj) ); + if (textDataObj && len > 0) + { + PRUnichar* text = nsnull; + textDataObj->ToString ( &text ); + stuffToPaste.Assign ( text, len / 2 ); + nsAutoEditBatch beginBatching(this); + rv = InsertAsQuotation(stuffToPaste, 0); + if (text) + nsMemory::Free(text); + } + } + nsCRT::free(flav); + } + + return rv; +} + +// Utility routine to make a new citer. This addrefs, of course. +static nsICiter* MakeACiter() +{ + // Make a citer of an appropriate type + nsICiter* citer = 0; + nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &rv); + if (NS_FAILED(rv)) return 0; + + char *citationType = 0; + rv = prefs->CopyCharPref("mail.compose.citationType", &citationType); + + if (NS_SUCCEEDED(rv) && citationType[0]) + { + if (!strncmp(citationType, "aol", 3)) + citer = new nsAOLCiter; + else + citer = new nsInternetCiter; + PL_strfree(citationType); + } + else + citer = new nsInternetCiter; + + if (citer) + NS_ADDREF(citer); + return citer; +} + +NS_IMETHODIMP +nsPlaintextEditor::InsertAsQuotation(const nsString& aQuotedText, + nsIDOMNode **aNodeInserted) +{ + // We have the text. Cite it appropriately: + nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter()); + + // Let the citer quote it for us: + nsString quotedStuff; + nsresult rv = citer->GetCiteString(aQuotedText, quotedStuff); + if (!NS_SUCCEEDED(rv)) + return rv; + + // It's best to put a blank line after the quoted text so that mails + // written without thinking won't be so ugly. + quotedStuff.Append(PRUnichar('\n')); + + nsCOMPtr<nsIDOMNode> preNode; + // get selection + nsCOMPtr<nsISelection> selection; + rv = GetSelection(getter_AddRefs(selection)); + if (NS_FAILED(rv)) return rv; + if (!selection) return NS_ERROR_NULL_POINTER; + + nsAutoEditBatch beginBatching(this); + nsAutoRules beginRulesSniffing(this, kOpInsertText, nsIEditor::eNext); + + // give rules a chance to handle or cancel + nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertElement); + PRBool cancel, handled; + rv = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled); + if (NS_FAILED(rv)) return rv; + if (cancel) return NS_OK; // rules canceled the operation + if (!handled) + { + rv = InsertText(quotedStuff.GetUnicode()); + + // XXX Should set *aNodeInserted to the first node inserted + if (aNodeInserted && NS_SUCCEEDED(rv)) + { + *aNodeInserted = 0; + //NS_IF_ADDREF(*aNodeInserted); + } + } + return rv; +} + +NS_IMETHODIMP +nsPlaintextEditor::PasteAsCitedQuotation(const nsString& aCitation, + PRInt32 aSelectionType) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPlaintextEditor::InsertAsCitedQuotation(const nsString& aQuotedText, + const nsString& aCitation, + PRBool aInsertHTML, + const nsString& aCharset, + nsIDOMNode **aNodeInserted) +{ + return InsertAsQuotation(aQuotedText, aNodeInserted); +} + +NS_IMETHODIMP +nsPlaintextEditor::Rewrap(PRBool aRespectNewlines) +{ + PRInt32 wrapCol; + nsresult rv = GetWrapWidth(&wrapCol); + if (NS_FAILED(rv)) + return NS_OK; +#ifdef DEBUG_akkana + printf("nsPlaintextEditor::Rewrap to %ld columns\n", (long)wrapCol); +#endif + + nsCOMPtr<nsISelection> selection; + rv = GetSelection(getter_AddRefs(selection)); + if (NS_FAILED(rv)) return rv; + + if (!selection) + return NS_ERROR_NOT_INITIALIZED; + PRBool isCollapsed; + rv = selection->GetIsCollapsed(&isCollapsed); + if (NS_FAILED(rv)) return rv; + + // Variables we'll need either way + nsAutoString format; format.AssignWithConversion("text/plain"); + nsAutoString current; + nsString wrapped; + + if (isCollapsed) // rewrap the whole document + { + rv = OutputToString(current, format, + nsIDocumentEncoder::OutputFormatted); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter()); + if (NS_FAILED(rv)) return rv; + if (!citer) return NS_ERROR_UNEXPECTED; + + rv = citer->Rewrap(current, wrapCol, 0, aRespectNewlines, wrapped); + if (NS_FAILED(rv)) return rv; + + rv = SelectAll(); + if (NS_FAILED(rv)) return rv; + + return InsertText(wrapped.GetUnicode()); + } + else // rewrap only the selection + { + rv = OutputToString(current, format, + nsIDocumentEncoder::OutputFormatted + | nsIDocumentEncoder::OutputSelectionOnly); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter()); + if (NS_FAILED(rv)) return rv; + if (!citer) return NS_ERROR_UNEXPECTED; + + PRUint32 firstLineOffset = 0; // XXX need to get this + rv = citer->Rewrap(current, wrapCol, firstLineOffset, aRespectNewlines, + wrapped); + if (NS_FAILED(rv)) return rv; + + return InsertText(wrapped.GetUnicode()); + } + return NS_OK; +} + +NS_IMETHODIMP +nsPlaintextEditor::StripCites() +{ +#ifdef DEBUG_akkana + printf("nsPlaintextEditor::StripCites()\n"); +#endif + + nsCOMPtr<nsISelection> selection; + nsresult rv = GetSelection(getter_AddRefs(selection)); + if (NS_FAILED(rv)) return rv; + + if (!selection) + return NS_ERROR_NOT_INITIALIZED; + PRBool isCollapsed; + rv = selection->GetIsCollapsed(&isCollapsed); + if (NS_FAILED(rv)) return rv; + + // Variables we'll need either way + nsAutoString format; format.AssignWithConversion("text/plain"); + nsAutoString current; + nsString stripped; + + if (isCollapsed) // rewrap the whole document + { + rv = OutputToString(current, format, + nsIDocumentEncoder::OutputFormatted); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter()); + if (NS_FAILED(rv)) return rv; + if (!citer) return NS_ERROR_UNEXPECTED; + + rv = citer->StripCites(current, stripped); + if (NS_FAILED(rv)) return rv; + + rv = SelectAll(); + if (NS_FAILED(rv)) return rv; + + return InsertText(stripped.GetUnicode()); + } + else // rewrap only the selection + { + rv = OutputToString(current, format, + nsIDocumentEncoder::OutputFormatted + | nsIDocumentEncoder::OutputSelectionOnly); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter()); + if (NS_FAILED(rv)) return rv; + if (!citer) return NS_ERROR_UNEXPECTED; + + rv = citer->StripCites(current, stripped); + if (NS_FAILED(rv)) return rv; + + return InsertText(stripped.GetUnicode()); + } + return NS_OK; +} + +NS_IMETHODIMP +nsPlaintextEditor::GetEmbeddedObjects(nsISupportsArray** aNodeList) +{ + *aNodeList = 0; + return NS_OK; +} + + #ifdef XP_MAC #pragma mark - #pragma mark nsIEditorIMESupport overrides diff --git a/mozilla/editor/libeditor/text/nsPlaintextEditor.h b/mozilla/editor/libeditor/text/nsPlaintextEditor.h index c2bc4435a22..bfe586880ec 100644 --- a/mozilla/editor/libeditor/text/nsPlaintextEditor.h +++ b/mozilla/editor/libeditor/text/nsPlaintextEditor.h @@ -26,12 +26,12 @@ #include "nsCOMPtr.h" #include "nsIPlaintextEditor.h" +#include "nsIEditorMailSupport.h" #include "nsEditor.h" #include "nsIDOMElement.h" #include "nsIDOMEventListener.h" -#include "TypeInState.h" #include "nsEditRules.h" class nsIDOMKeyEvent; @@ -44,7 +44,8 @@ class nsIDocumentEncoder; * Use to edit text document represented as a DOM tree. */ class nsPlaintextEditor : public nsEditor, - public nsIPlaintextEditor + public nsIPlaintextEditor, + public nsIEditorMailSupport { public: @@ -67,6 +68,21 @@ public: /* ------------ nsIPlaintextEditor methods -------------- */ NS_DECL_NSIPLAINTEXTEDITOR + /* ------------ nsIEditorMailSupport overrides -------------- */ + NS_IMETHOD PasteAsQuotation(PRInt32 aSelectionType); + NS_IMETHOD InsertAsQuotation(const nsString& aQuotedText, + nsIDOMNode** aNodeInserted); + NS_IMETHOD PasteAsCitedQuotation(const nsString& aCitation, + PRInt32 aSelectionType); + NS_IMETHOD InsertAsCitedQuotation(const nsString& aQuotedText, + const nsString& aCitation, + PRBool aInsertHTML, + const nsString& aCharset, + nsIDOMNode** aNodeInserted); + NS_IMETHOD Rewrap(PRBool aRespectNewlines); + NS_IMETHOD StripCites(); + NS_IMETHOD GetEmbeddedObjects(nsISupportsArray** aNodeList); + /* ------------ nsIEditorIMESupport overrides -------------- */ NS_IMETHOD SetCompositionString(const nsString& aCompositionString, nsIPrivateTextRangeList* aTextRangeList,nsTextEventReply* aReply); @@ -212,11 +228,6 @@ protected: PRInt32 mMaxTextLength; PRInt32 mInitTriggerCounter; -public: - static nsIAtom *gTypingTxnName; - static nsIAtom *gIMETxnName; - static nsIAtom *gDeleteTxnName; - // friends friend class nsHTMLEditRules; friend class nsTextEditRules; diff --git a/mozilla/editor/libeditor/text/nsTextEditRules.cpp b/mozilla/editor/libeditor/text/nsTextEditRules.cpp index cf864354653..62b116eb4c3 100644 --- a/mozilla/editor/libeditor/text/nsTextEditRules.cpp +++ b/mozilla/editor/libeditor/text/nsTextEditRules.cpp @@ -23,7 +23,7 @@ #include "nsTextEditRules.h" #include "nsEditor.h" -#include "nsHTMLEditUtils.h" +#include "nsTextEditUtils.h" #include "nsCOMPtr.h" #include "nsIDOMNode.h" @@ -37,10 +37,8 @@ #include "nsIContentIterator.h" #include "nsIEnumerator.h" #include "nsLayoutCID.h" -#include "nsIEditProperty.h" #include "nsEditorUtils.h" #include "EditTxn.h" -#include "TypeInState.h" #include "nsIPref.h" #ifdef IBMBIDI #include "nsIPresContext.h" @@ -165,8 +163,6 @@ nsTextEditRules::SetFlags(PRUint32 aFlags) // SetFlags() is really meant to only be called once // and at editor init time. - PRBool willBePlaintext = (aFlags & nsIPlaintextEditor::eEditorPlaintextMask) != 0; - PRBool alreadyPlaintext = (mFlags & nsIPlaintextEditor::eEditorPlaintextMask) != 0; mFlags = aFlags; return NS_OK; } @@ -422,7 +418,7 @@ nsTextEditRules::DidInsertBreak(nsISelection *aSelection, nsresult aResult) temp = mEditor->GetChildAt(selNode, selOffset); if (temp) return NS_OK; // cant be at end of there is a node after us. nearNode = mEditor->GetChildAt(selNode, selOffset-1); - if (nearNode && nsHTMLEditUtils::IsBreak(nearNode) && !nsHTMLEditUtils::IsMozBR(nearNode)) + if (nearNode && nsTextEditUtils::IsBreak(nearNode) && !nsTextEditUtils::IsMozBR(nearNode)) { nsCOMPtr<nsISelection> sel(aSelection); nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(sel)); diff --git a/mozilla/editor/public/nsIEditor.h b/mozilla/editor/public/nsIEditor.h index ea89c315c48..c1e1f9b6dfa 100644 --- a/mozilla/editor/public/nsIEditor.h +++ b/mozilla/editor/public/nsIEditor.h @@ -323,14 +323,6 @@ public: /* ------------ Node manipulation methods -------------- */ - /** - * Tests if a node is a BLOCK element according the the HTML 4.0 DTD - * This does NOT consider CSS effect on display type - * - * @param aNode the node to test - */ - NS_IMETHOD NodeIsBlock(nsIDOMNode *aNode, PRBool &aIsBlock)=0; - /** * SetAttribute() sets the attribute of aElement. * No checking is done to see if aAttribute is a legal attribute of the node, diff --git a/mozilla/editor/public/nsIEditorMailSupport.h b/mozilla/editor/public/nsIEditorMailSupport.h index 0a5392b010a..5e800b2e6b6 100644 --- a/mozilla/editor/public/nsIEditorMailSupport.h +++ b/mozilla/editor/public/nsIEditorMailSupport.h @@ -31,7 +31,7 @@ class nsString; class nsISupportsArray; - +class nsIDOMNode; class nsIEditorMailSupport : public nsISupports { @@ -39,33 +39,39 @@ public: static const nsIID& GetIID() { static nsIID iid = NS_IEDITORMAILSUPPORT_IID; return iid; } - /** paste the text in the OS clipboard at the cursor position + /** Paste the text in the OS clipboard at the cursor position, * as a quotation (whose representation is dependant on the editor type), - * replacing the selected text (if any) - * @param aCitation The "mid" URL of the source message + * replacing the selected text (if any). + * @param aSelectionType Text or html? */ NS_IMETHOD PasteAsQuotation(PRInt32 aSelectionType)=0; - /** insert a string as quoted text, - * as a quotation (whose representation is dependant on the editor type), - * replacing the selected text (if any) + /** Insert a string as quoted text + * (whose representation is dependant on the editor type), + * replacing the selected text (if any). * @param aQuotedText The actual text to be quoted - * @param aCitation The "mid" URL of the source message */ NS_IMETHOD InsertAsQuotation(const nsString& aQuotedText, nsIDOMNode** aNodeInserted)=0; - /** - * Document me! - * - */ + /** Paste a string as quoted text, + * as a quotation (whose representation is dependant on the editor type), + * replacing the selected text (if any) + * @param aCitation The "mid" URL of the source message + * @param aSelectionType Text or html? + */ NS_IMETHOD PasteAsCitedQuotation(const nsString& aCitation, PRInt32 aSelectionType)=0; - /** - * Document me! - * - */ + /** Insert a string as quoted text + * (whose representation is dependant on the editor type), + * replacing the selected text (if any), + * including, if possible, a "cite" attribute. + * @param aQuotedText The actual text to be quoted + * @param aCitation The "mid" URL of the source message + * @param aInsertHTML Insert as html? (vs plaintext) + * @param aCharset The charset of the text to be inserted + */ NS_IMETHOD InsertAsCitedQuotation(const nsString& aQuotedText, const nsString& aCitation, PRBool aInsertHTML, @@ -73,11 +79,21 @@ public: nsIDOMNode** aNodeInserted)=0; /** - * Document me! - * + * Rewrap the selected part of the document, re-quoting if necessary. + * @param aRespectNewlines Try to maintain newlines in the original? + */ + NS_IMETHOD Rewrap(PRBool aRespectNewlines)=0; + + /** + * Strip any citations in the selected part of the document. + */ + NS_IMETHOD StripCites()=0; + + + /** + * Get a list of IMG and OBJECT tags in the current document. */ NS_IMETHOD GetEmbeddedObjects(nsISupportsArray** aNodeList)=0; - }; diff --git a/mozilla/editor/public/nsIHTMLEditor.h b/mozilla/editor/public/nsIHTMLEditor.h index 55329547dc2..defe80e23b6 100644 --- a/mozilla/editor/public/nsIHTMLEditor.h +++ b/mozilla/editor/public/nsIHTMLEditor.h @@ -132,6 +132,14 @@ public: /* ------------ HTML content methods -------------- */ + /** + * Tests if a node is a BLOCK element according the the HTML 4.0 DTD + * This does NOT consider CSS effect on display type + * + * @param aNode the node to test + */ + NS_IMETHOD NodeIsBlock(nsIDOMNode *aNode, PRBool &aIsBlock)=0; + /** * Insert some HTML source at the current location *