diff --git a/mozilla/editor/libeditor/base/nsEditor.cpp b/mozilla/editor/libeditor/base/nsEditor.cpp index b539914aef4..3a8c7693c5a 100644 --- a/mozilla/editor/libeditor/base/nsEditor.cpp +++ b/mozilla/editor/libeditor/base/nsEditor.cpp @@ -3378,7 +3378,8 @@ nsEditor::GetNextNodeImpl(nsIDOMNode *aCurrentNode, nsCOMPtr -nsEditor::GetRightmostChild(nsIDOMNode *aCurrentNode, PRBool bNoBlockCrossing) +nsEditor::GetRightmostChild(nsIDOMNode *aCurrentNode, + PRBool bNoBlockCrossing) { if (!aCurrentNode) return nsnull; nsCOMPtr resultNode, temp=aCurrentNode; @@ -3402,7 +3403,8 @@ nsEditor::GetRightmostChild(nsIDOMNode *aCurrentNode, PRBool bNoBlockCrossing) } nsCOMPtr -nsEditor::GetLeftmostChild(nsIDOMNode *aCurrentNode, PRBool bNoBlockCrossing) +nsEditor::GetLeftmostChild(nsIDOMNode *aCurrentNode, + PRBool bNoBlockCrossing) { if (!aCurrentNode) return nsnull; nsCOMPtr resultNode, temp=aCurrentNode; diff --git a/mozilla/editor/libeditor/base/nsEditor.h b/mozilla/editor/libeditor/base/nsEditor.h index 5e864ceedcb..86d4692c7e4 100644 --- a/mozilla/editor/libeditor/base/nsEditor.h +++ b/mozilla/editor/libeditor/base/nsEditor.h @@ -438,7 +438,7 @@ public: * return nsnull if aCurrentNode has no children. */ nsCOMPtr GetLeftmostChild(nsIDOMNode *aCurrentNode, - PRBool bNoBlockCrossing = PR_FALSE); + PRBool bNoBlockCrossing = PR_FALSE); /** returns PR_TRUE if aNode is of the type implied by aTag */ static PRBool NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag); diff --git a/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp b/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp index 660ba9dc593..af87456cdf4 100644 --- a/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp @@ -42,6 +42,7 @@ #include "nsHTMLEditRules.h" #include "nsTextEditUtils.h" #include "nsHTMLEditUtils.h" +#include "nsWSRunObject.h" #include "nsEditorEventListeners.h" @@ -379,6 +380,20 @@ nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsAString & aInputString, if (!parentNode) res = NS_ERROR_FAILURE; if (NS_FAILED(res)) return res; + // if there are any invisible br's after our insertion point, remove them. + // this is because if there is a br at end of what we paste, it will make + // the invisible br visible. + nsWSRunObject wsObj(this, parentNode, offsetOfNewNode); + if ( nsTextEditUtils::IsBreak(wsObj.mEndReasonNode) && + !IsVisBreak(wsObj.mEndReasonNode) ) + { + res = DeleteNode(wsObj.mEndReasonNode); + if (NS_FAILED(res)) return res; + } + + // remeber if we are in a link. + PRBool bStartedInLink = IsInLink(parentNode); + // are we in a text node? If so, split it. if (IsTextNode(parentNode)) { @@ -589,9 +604,96 @@ nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsAString & aInputString, // Now collapse the selection to the end of what we just inserted: if (lastInsertNode) { - res = GetNodeLocation(lastInsertNode, address_of(parentNode), &offsetOfNewNode); - NS_ENSURE_SUCCESS(res, res); - selection->Collapse(parentNode, offsetOfNewNode+1); + // set selection to the end of what we just pasted. + nsCOMPtr selNode, tmp, visNode, highTable; + PRInt32 selOffset; + + // but dont cross tables + if (!nsHTMLEditUtils::IsTable(lastInsertNode)) + { + res = GetLastEditableLeaf(lastInsertNode, address_of(selNode)); + if (NS_FAILED(res)) return res; + tmp = selNode; + while (tmp && (tmp != lastInsertNode)) + { + if (nsHTMLEditUtils::IsTable(tmp)) + highTable = tmp; + nsCOMPtr parent = tmp; + tmp->GetParentNode(getter_AddRefs(parent)); + tmp = parent; + } + if (highTable) + selNode = highTable; + } + if (!selNode) + selNode = lastInsertNode; + if (IsTextNode(selNode) || (IsContainer(selNode) && !nsHTMLEditUtils::IsTable(selNode))) + { + res = GetLengthOfDOMNode(selNode, (PRUint32&)selOffset); + if (NS_FAILED(res)) return res; + } + else // we need to find a container for selection. Look up. + { + tmp = selNode; + res = GetNodeLocation(tmp, address_of(selNode), &selOffset); + ++selOffset; // want to be *after* last leaf node in paste + if (NS_FAILED(res)) return res; + } + + // make sure we dont end up with selection collapsed after an invisible break node + nsWSRunObject wsRunObj(this, selNode, selOffset); + PRInt32 outVisOffset=0; + PRInt16 visType=0; + res = wsRunObj.PriorVisibleNode(selNode, selOffset, address_of(visNode), &outVisOffset, &visType); + if (NS_FAILED(res)) return res; + if (visType == nsWSRunObject::eBreak) + { + // we are after a break. Is it visible? Despite the name, + // PriorVisibleNode does not make that determination for breaks. + // It also may not return the break in visNode. We have to pull it + // out of the nsWSRunObject's state. + if (!IsVisBreak(wsRunObj.mStartReasonNode)) + { + // dont leave selection past an invisible break; + // reset {selNode,selOffset} to point before break + res = GetNodeLocation(wsRunObj.mStartReasonNode, address_of(selNode), &selOffset); + // we want to be inside any inline style prior to break + nsWSRunObject wsRunObj(this, selNode, selOffset); + res = wsRunObj.PriorVisibleNode(selNode, selOffset, address_of(visNode), &outVisOffset, &visType); + if (NS_FAILED(res)) return res; + if (visType == nsWSRunObject::eText || + visType == nsWSRunObject::eNormalWS) + { + selNode = visNode; + selOffset = outVisOffset; // PriorVisibleNode already set offset to _after_ the text or ws + } + else if (visType == nsWSRunObject::eSpecial) + { + // prior visible thing is an image or some other non-text thingy. + // We want to be right after it. + res = GetNodeLocation(wsRunObj.mStartReasonNode, address_of(selNode), &selOffset); + ++selOffset; + } + } + } + selection->Collapse(selNode, selOffset); + + // if we just pasted a link, discontinue link style + nsCOMPtr link; + if (!bStartedInLink && IsInLink(selNode, address_of(link))) + { + // so, if we just pasted a link, I split it. Why do that instead of just + // nudging selection point beyond it? Because it might have ended in a BR + // that is not visible. If so, the code above just placed selection + // inside that. So I split it instead. + nsCOMPtr leftLink; + PRInt32 linkOffset; + res = SplitNodeDeep(link, selNode, selOffset, &linkOffset, PR_TRUE, address_of(leftLink)); + if (NS_FAILED(res)) return res; + res = GetNodeLocation(leftLink, address_of(selNode), &selOffset); + if (NS_FAILED(res)) return res; + selection->Collapse(selNode, selOffset+1); + } } } @@ -599,6 +701,30 @@ nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsAString & aInputString, return res; } + +PRBool +nsHTMLEditor::IsInLink(nsIDOMNode *aNode, nsCOMPtr *outLink) +{ + if (!aNode) + return PR_FALSE; + if (outLink) + *outLink = nsnull; + nsCOMPtr tmp, node = aNode; + while (node) + { + if (nsHTMLEditUtils::IsLink(node)) + { + if (outLink) + *outLink = node; + return PR_TRUE; + } + tmp = node; + tmp->GetParentNode(getter_AddRefs(node)); + } + return PR_FALSE; +} + + nsresult nsHTMLEditor::StripFormattingNodes(nsIDOMNode *aNode, PRBool aListOnly) { diff --git a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp index bfa6d8902e4..2dd4cba749e 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp @@ -2708,6 +2708,17 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection, res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset); if (NS_FAILED(res)) return res; + // make sure we dont assemble content that is in different table cells into the same list. + // respect table cell boundaries when listifying. + if (curList) + { + PRBool bInDifTblElems; + res = InDifferentTableElements(curList, curNode, &bInDifTblElems); + if (NS_FAILED(res)) return res; + if (bInDifTblElems) + curList = nsnull; + } + // if curNode is a Break, delete it, and quit remembering prev list item if (nsTextEditUtils::IsBreak(curNode)) { @@ -2819,9 +2830,8 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection, continue; } - // need to make a list to put things in if we haven't already, - // or if this node doesn't go in list we used earlier. - if (!curList) // || transitionList[i]) + // need to make a list to put things in if we haven't already + if (!curList) { res = SplitAsNeeded(aListType, address_of(curParent), &offset); if (NS_FAILED(res)) return res; @@ -4908,7 +4918,7 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt // the promotion altogether. We have a br after us. If we fell through to code below, // it would think br was before us and would proceed merrily along. node = nsEditor::GetChildAt(parent,offset); - if (node && nsTextEditUtils::IsBreak(node)) + if (node && mHTMLEditor->IsVisBreak(node)) return NS_OK; // default values used. } node = nsEditor::GetChildAt(parent,offset); @@ -4930,7 +4940,7 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt nextNodeBlock = nsHTMLEditor::GetBlockNodeParent(nextNode); if (nextNodeBlock != block) break; - if (nsTextEditUtils::IsBreak(nextNode)) + if (mHTMLEditor->IsVisBreak(nextNode)) { node = nextNode; break; @@ -5885,7 +5895,7 @@ nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection, // just fall out to default of inserting a BR return res; } - if (IsVisBreak(sibling) && !nsTextEditUtils::HasMozAttr(sibling)) + if (mHTMLEditor->IsVisBreak(sibling) && !nsTextEditUtils::HasMozAttr(sibling)) { // split para nsCOMPtr selNode = aNode; @@ -5906,7 +5916,7 @@ nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection, // just fall out to default of inserting a BR return res; } - if (IsVisBreak(sibling) && !nsTextEditUtils::HasMozAttr(sibling)) + if (mHTMLEditor->IsVisBreak(sibling) && !nsTextEditUtils::HasMozAttr(sibling)) { // split para nsCOMPtr selNode = aNode; @@ -5927,12 +5937,12 @@ nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection, nsCOMPtr nearNode, selNode = aNode; res = mHTMLEditor->GetPriorHTMLNode(aNode, aOffset, address_of(nearNode)); if (NS_FAILED(res)) return res; - if (!nearNode || !IsVisBreak(nearNode) || nsTextEditUtils::HasMozAttr(nearNode)) + if (!nearNode || !mHTMLEditor->IsVisBreak(nearNode) || nsTextEditUtils::HasMozAttr(nearNode)) { // is there a BR after it? res = mHTMLEditor->GetNextHTMLNode(aNode, aOffset, address_of(nearNode)); if (NS_FAILED(res)) return res; - if (!nearNode || !IsVisBreak(nearNode) || nsTextEditUtils::HasMozAttr(nearNode)) + if (!nearNode || !mHTMLEditor->IsVisBreak(nearNode) || nsTextEditUtils::HasMozAttr(nearNode)) { // just fall out to default of inserting a BR return res; @@ -5972,7 +5982,7 @@ nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara, address_of(leftPara), address_of(rightPara)); if (NS_FAILED(res)) return res; // get rid of the break, if it is visible (otherwise it may be needed to prevent an empty p) - if (IsVisBreak(aBRNode)) + if (mHTMLEditor->IsVisBreak(aBRNode)) { res = mHTMLEditor->DeleteNode(aBRNode); if (NS_FAILED(res)) return res; @@ -6903,7 +6913,7 @@ nsHTMLEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection { if (nearNode && nsTextEditUtils::IsBreak(nearNode) ) { - if (!IsVisBreak(nearNode)) + if (!mHTMLEditor->IsVisBreak(nearNode)) { // need to insert special moz BR. Why? Because if we don't // the user will see no new line for the break. Also, things @@ -6976,24 +6986,6 @@ nsHTMLEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection } -PRBool -nsHTMLEditRules::IsVisBreak(nsIDOMNode *aNode) -{ - if (!aNode) - return PR_FALSE; - if (!nsTextEditUtils::IsBreak(aNode)) - return PR_FALSE; - // check if there is a later node in block after br - nsCOMPtr nextNode; - mHTMLEditor->GetNextHTMLNode(aNode, address_of(nextNode), PR_TRUE); - if (!nextNode) - return PR_FALSE; // this break is trailer in block, it's not visible - if (IsBlockNode(nextNode)) - return PR_FALSE; // break is right before a block, it's not visible - return PR_TRUE; -} - - nsresult nsHTMLEditRules::FindNearSelectableNode(nsIDOMNode *aSelNode, PRInt32 aSelOffset, @@ -7028,7 +7020,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) - || IsVisBreak(nearNode) + || nsTextEditUtils::IsBreak(nearNode) || nsHTMLEditUtils::IsImage(nearNode))) { curNode = nearNode; diff --git a/mozilla/editor/libeditor/html/nsHTMLEditRules.h b/mozilla/editor/libeditor/html/nsHTMLEditRules.h index 22dabd4195e..4581a7da457 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditRules.h +++ b/mozilla/editor/libeditor/html/nsHTMLEditRules.h @@ -245,7 +245,6 @@ protected: nsresult UpdateDocChangeRange(nsIDOMRange *aRange); nsresult ConfirmSelectionInBody(); nsresult InsertMozBRIfNeeded(nsIDOMNode *aNode); - PRBool IsVisBreak(nsIDOMNode *aNode); PRBool IsEmptyInline(nsIDOMNode *aNode); PRBool ListIsEmptyLine(nsISupportsArray *arrayOfNodes); nsresult RemoveAlignment(nsIDOMNode * aNode, const nsAString & aAlignType, PRBool aChildrenOnly); diff --git a/mozilla/editor/libeditor/html/nsHTMLEditUtils.cpp b/mozilla/editor/libeditor/html/nsHTMLEditUtils.cpp index 1af3fb04562..5b9f6813e7f 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditUtils.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditUtils.cpp @@ -426,6 +426,14 @@ nsHTMLEditUtils::IsDescendantOf(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 return PR_FALSE; } +PRBool +nsHTMLEditUtils::IsLeafNode(nsIDOMNode *aNode) +{ + if (!aNode) return PR_FALSE; + PRBool hasChildren = PR_FALSE; + aNode->HasChildNodes(&hasChildren); + return !hasChildren; +} PRBool nsHTMLEditUtils::SupportsAlignAttr(nsIDOMNode * aNode) diff --git a/mozilla/editor/libeditor/html/nsHTMLEditUtils.h b/mozilla/editor/libeditor/html/nsHTMLEditUtils.h index 2037dd93af6..694b46b112b 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditUtils.h +++ b/mozilla/editor/libeditor/html/nsHTMLEditUtils.h @@ -76,6 +76,7 @@ public: static PRBool IsMailCite(nsIDOMNode *aNode); static PRBool IsFormWidget(nsIDOMNode *aNode); static PRBool IsDescendantOf(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 *aOffset = 0); + static PRBool IsLeafNode(nsIDOMNode *aNode); static PRBool SupportsAlignAttr(nsIDOMNode *aNode); }; diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp index 61b760253ec..3e5886bbe25 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp @@ -56,6 +56,7 @@ #include "nsICSSParser.h" #include "nsIDOMCSSStyleRule.h" #include "nsIDOMText.h" +#include "nsITextContent.h" #include "nsIDOMNodeList.h" #include "nsIDOMDocument.h" #include "nsIDOMAttr.h" @@ -112,6 +113,10 @@ #include "SetDocTitleTxn.h" #include "nsGUIEvent.h" +#define _IMPL_NS_LAYOUT +#include "nsTextFragment.h" +#undef _IMPL_NS_LAYOUT + // netwerk #include "nsIURI.h" #include "nsNetUtil.h" @@ -1096,6 +1101,42 @@ nsHTMLEditor::IsPrevCharWhitespace(nsIDOMNode *aParentNode, /* ------------ End Block methods -------------- */ +PRBool nsHTMLEditor::IsVisBreak(nsIDOMNode *aNode) +{ + if (!aNode) + return PR_FALSE; + if (!nsTextEditUtils::IsBreak(aNode)) + return PR_FALSE; + // check if there is a later node in block after br + nsCOMPtr priorNode, nextNode; + GetPriorHTMLNode(aNode, address_of(priorNode), PR_TRUE); + GetNextHTMLNode(aNode, address_of(nextNode), PR_TRUE); + // if we are next to another break, we are visible + if (priorNode && nsTextEditUtils::IsBreak(priorNode)) + return PR_TRUE; + if (nextNode && nsTextEditUtils::IsBreak(nextNode)) + return PR_TRUE; + + // if we are right before block boundary, then br not visible + if (!nextNode) + return PR_FALSE; // this break is trailer in block, it's not visible + if (IsBlockNode(nextNode)) + return PR_FALSE; // break is right before a block, it's not visible + + // sigh. We have to use expensive whitespace calculation code to + // determine what is going on + nsCOMPtr selNode, tmp; + PRInt32 selOffset; + GetNodeLocation(aNode, address_of(selNode), &selOffset); + selOffset++; // lets look after the break + nsWSRunObject wsObj(this, selNode, selOffset); + if (wsObj.mEndReason | nsWSRunObject::eBlock) + return PR_FALSE; + + return PR_TRUE; +} + + PRBool nsHTMLEditor::IsModifiable() { PRUint32 flags; @@ -4824,9 +4865,9 @@ nsHTMLEditor::GetFirstEditableLeaf( nsIDOMNode *aNode, nsCOMPtr *aOu *aOutFirstLeaf = child; return res; } +#endif -// jfrancis or glazman may want to use this method (currently it's unused) nsresult nsHTMLEditor::GetLastEditableLeaf( nsIDOMNode *aNode, nsCOMPtr *aOutLastLeaf) { @@ -4839,7 +4880,7 @@ nsHTMLEditor::GetLastEditableLeaf( nsIDOMNode *aNode, nsCOMPtr *aOut // find rightmost leaf nsCOMPtr child; nsresult res = NS_OK; - child = GetRightmostChild(aNode); + child = GetRightmostChild(aNode, PR_FALSE); while (child && (!IsEditable(child) || !nsHTMLEditUtils::IsLeafNode(child))) { nsCOMPtr tmp; @@ -4859,7 +4900,6 @@ nsHTMLEditor::GetLastEditableLeaf( nsIDOMNode *aNode, nsCOMPtr *aOut *aOutLastLeaf = child; return res; } -#endif diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.h b/mozilla/editor/libeditor/html/nsHTMLEditor.h index 4f33779ef66..6ec3da522c3 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.h +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.h @@ -621,6 +621,7 @@ protected: const nsAString & aCharset, const nsAString & aContextStr, const nsAString & aInfoStr); + PRBool IsInLink(nsIDOMNode *aNode, nsCOMPtr *outLink = nsnull); nsresult StripFormattingNodes(nsIDOMNode *aNode, PRBool aOnlyList = PR_FALSE); nsresult CreateDOMFragmentFromPaste(nsIDOMNSRange *aNSRange, const nsAString & aInputString, @@ -652,6 +653,9 @@ protected: /** simple utility to handle any error with event listener allocation or registration */ void HandleEventListenerError(); + /* small utility routine to test if a break node is visible to user */ + PRBool IsVisBreak(nsIDOMNode *aNode); + /* small utility routine to test the eEditorReadonly bit */ PRBool IsModifiable(); @@ -726,8 +730,8 @@ protected: #ifdef XXX_DEAD_CODE // these should be removed some day by jfrancis: GetFirstEditableLeaf & GetLastEditableLeaf nsresult GetFirstEditableLeaf( nsIDOMNode *aNode, nsCOMPtr *aOutFirstLeaf); - nsresult GetLastEditableLeaf( nsIDOMNode *aNode, nsCOMPtr *aOutLastLeaf); #endif + nsresult GetLastEditableLeaf( nsIDOMNode *aNode, nsCOMPtr *aOutLastLeaf); nsresult GetDOMEventReceiver(nsIDOMEventReceiver **aEventReceiver); diff --git a/mozilla/editor/libeditor/html/nsWSRunObject.h b/mozilla/editor/libeditor/html/nsWSRunObject.h index cb43408fd74..87ad4d1f179 100644 --- a/mozilla/editor/libeditor/html/nsWSRunObject.h +++ b/mozilla/editor/libeditor/html/nsWSRunObject.h @@ -345,6 +345,7 @@ class nsWSRunObject nsHTMLEditor *mHTMLEditor; // non-owning. friend class nsHTMLEditRules; // opening this class up for pillaging + friend class nsHTMLEditor; // opening this class up for more pillaging }; #endif