diff --git a/editor/libeditor/html/nsHTMLEditRules.cpp b/editor/libeditor/html/nsHTMLEditRules.cpp
index 13f2a370f00e..b1ba9c9741d4 100644
--- a/editor/libeditor/html/nsHTMLEditRules.cpp
+++ b/editor/libeditor/html/nsHTMLEditRules.cpp
@@ -1424,8 +1424,7 @@ nsresult
nsHTMLEditRules::WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled)
{
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
- nsCOMPtr selection(aSelection);
- nsCOMPtr selPriv(do_QueryInterface(selection));
+ nsCOMPtr selPriv(do_QueryInterface(aSelection));
// initialize out param
*aCancel = PR_FALSE;
*aHandled = PR_FALSE;
@@ -1453,51 +1452,9 @@ nsHTMLEditRules::WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBo
// should we abort this if we encounter table cell boundaries?
if (mFlags & nsIPlaintextEditor::eEditorMailMask)
{
- nsCOMPtr citeNode, selNode, leftCite, rightCite;
- PRInt32 selOffset, newOffset;
- res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
+ res = SplitMailCites(aSelection, bPlaintext, aHandled);
if (NS_FAILED(res)) return res;
- res = GetTopEnclosingMailCite(selNode, address_of(citeNode), bPlaintext);
- if (NS_FAILED(res)) return res;
- if (citeNode)
- {
- nsCOMPtr brNode;
- res = mHTMLEditor->SplitNodeDeep(citeNode, selNode, selOffset, &newOffset,
- PR_TRUE, address_of(leftCite), address_of(rightCite));
- if (NS_FAILED(res)) return res;
- res = citeNode->GetParentNode(getter_AddRefs(selNode));
- if (NS_FAILED(res)) return res;
- res = mHTMLEditor->CreateBR(selNode, newOffset, address_of(brNode));
- if (NS_FAILED(res)) return res;
- // want selection before the break, and on same line
- selPriv->SetInterlinePosition(PR_TRUE);
- res = aSelection->Collapse(selNode, newOffset);
- if (NS_FAILED(res)) return res;
- // if citeNode wasn't a block, we also want another break before it
- if (IsInlineNode(citeNode))
- {
- res = mHTMLEditor->CreateBR(selNode, newOffset, address_of(brNode));
- if (NS_FAILED(res)) return res;
- }
- // delete any empty cites
- PRBool bEmptyCite = PR_FALSE;
- if (leftCite)
- {
- res = mHTMLEditor->IsEmptyNode(leftCite, &bEmptyCite, PR_TRUE, PR_FALSE);
- if (NS_SUCCEEDED(res) && bEmptyCite)
- res = mHTMLEditor->DeleteNode(leftCite);
- if (NS_FAILED(res)) return res;
- }
- if (rightCite)
- {
- res = mHTMLEditor->IsEmptyNode(rightCite, &bEmptyCite, PR_TRUE, PR_FALSE);
- if (NS_SUCCEEDED(res) && bEmptyCite)
- res = mHTMLEditor->DeleteNode(rightCite);
- if (NS_FAILED(res)) return res;
- }
- *aHandled = PR_TRUE;
- return NS_OK;
- }
+ if (*aHandled) return NS_OK;
}
// smart splitting rules
@@ -1586,6 +1543,110 @@ nsHTMLEditRules::DidInsertBreak(nsISelection *aSelection, nsresult aResult)
}
+nsresult
+nsHTMLEditRules::SplitMailCites(nsISelection *aSelection, PRBool aPlaintext, PRBool *aHandled)
+{
+ if (!aSelection || !aHandled)
+ return NS_ERROR_NULL_POINTER;
+ nsCOMPtr selPriv(do_QueryInterface(aSelection));
+ nsCOMPtr citeNode, selNode, leftCite, rightCite;
+ PRInt32 selOffset, newOffset;
+ nsresult res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
+ if (NS_FAILED(res)) return res;
+ res = GetTopEnclosingMailCite(selNode, address_of(citeNode), aPlaintext);
+ if (NS_FAILED(res)) return res;
+ if (citeNode)
+ {
+ if (IsInlineNode(citeNode))
+ {
+ // this is getting messy. If our selection is just before a break, nudge it to be
+ // just after it. This does two things for us. It saves us the trouble of having to add
+ // a break here ourselves to preserve the "blockness" of the inline span mailquote, and
+ // it means the break wont end up making an empty line that happens to be inside a
+ // mailquote. The latter can confuse a user if they click there and start typing,
+ // because being in the mailquote may affect wrapping behavior, or font color, etc.
+ nsWSRunObject wsObj(mHTMLEditor, selNode, newOffset);
+ nsCOMPtr visNode;
+ PRInt32 visOffset=0;
+ PRInt16 wsType;
+ res = wsObj.NextVisibleNode(selNode, selOffset, address_of(visNode), &visOffset, &wsType);
+ if (NS_FAILED(res)) return res;
+ if (wsType==nsWSRunObject::eBreak)
+ {
+ // ok, we are just before a break. is it inside the mailquote?
+ PRInt32 unused;
+ if (nsHTMLEditUtils::IsDescendantOf(visNode, citeNode, &unused))
+ {
+ // it is. so lets reset our selection to be just after it.
+ res = mHTMLEditor->GetNodeLocation(visNode, address_of(selNode), &selOffset);
+ if (NS_FAILED(res)) return res;
+ ++selOffset;
+ }
+ }
+ }
+
+ nsCOMPtr brNode;
+ res = mHTMLEditor->SplitNodeDeep(citeNode, selNode, selOffset, &newOffset,
+ PR_TRUE, address_of(leftCite), address_of(rightCite));
+ if (NS_FAILED(res)) return res;
+ res = citeNode->GetParentNode(getter_AddRefs(selNode));
+ if (NS_FAILED(res)) return res;
+ res = mHTMLEditor->CreateBR(selNode, newOffset, address_of(brNode));
+ if (NS_FAILED(res)) return res;
+ // want selection before the break, and on same line
+ selPriv->SetInterlinePosition(PR_TRUE);
+ res = aSelection->Collapse(selNode, newOffset);
+ if (NS_FAILED(res)) return res;
+ // if citeNode wasn't a block, we might also want another break before it.
+ // We need to examine the content both before the br we just added and also
+ // just after it. If we dont have another br or block boundary adjacent,
+ // then we will ned a 2nd br added to achieve blank line that user expects.
+ if (IsInlineNode(citeNode))
+ {
+ nsWSRunObject wsObj(mHTMLEditor, selNode, newOffset);
+ nsCOMPtr visNode;
+ PRInt32 visOffset=0;
+ PRInt16 wsType;
+ res = wsObj.PriorVisibleNode(selNode, newOffset, address_of(visNode), &visOffset, &wsType);
+ if (NS_FAILED(res)) return res;
+ if ((wsType==nsWSRunObject::eNormalWS) ||
+ (wsType==nsWSRunObject::eText) ||
+ (wsType==nsWSRunObject::eSpecial))
+ {
+ nsWSRunObject wsObjAfterBR(mHTMLEditor, selNode, newOffset+1);
+ res = wsObj.NextVisibleNode(selNode, newOffset, address_of(visNode), &visOffset, &wsType);
+ if (NS_FAILED(res)) return res;
+ if ((wsType==nsWSRunObject::eNormalWS) ||
+ (wsType==nsWSRunObject::eText) ||
+ (wsType==nsWSRunObject::eSpecial))
+ {
+ res = mHTMLEditor->CreateBR(selNode, newOffset, address_of(brNode));
+ if (NS_FAILED(res)) return res;
+ }
+ }
+ }
+ // delete any empty cites
+ PRBool bEmptyCite = PR_FALSE;
+ if (leftCite)
+ {
+ res = mHTMLEditor->IsEmptyNode(leftCite, &bEmptyCite, PR_TRUE, PR_FALSE);
+ if (NS_SUCCEEDED(res) && bEmptyCite)
+ res = mHTMLEditor->DeleteNode(leftCite);
+ if (NS_FAILED(res)) return res;
+ }
+ if (rightCite)
+ {
+ res = mHTMLEditor->IsEmptyNode(rightCite, &bEmptyCite, PR_TRUE, PR_FALSE);
+ if (NS_SUCCEEDED(res) && bEmptyCite)
+ res = mHTMLEditor->DeleteNode(rightCite);
+ if (NS_FAILED(res)) return res;
+ }
+ *aHandled = PR_TRUE;
+ }
+ return NS_OK;
+}
+
+
nsresult
nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
nsIEditor::EDirection aAction,
@@ -2837,7 +2898,7 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection,
continue;
}
- // need to make a list to put things in if we haven't already
+ // need to make a list to put things in if we haven't already,
if (!curList)
{
res = SplitAsNeeded(aListType, address_of(curParent), &offset);
diff --git a/editor/libeditor/html/nsHTMLEditRules.h b/editor/libeditor/html/nsHTMLEditRules.h
index 4581a7da457f..710c555d178c 100644
--- a/editor/libeditor/html/nsHTMLEditRules.h
+++ b/editor/libeditor/html/nsHTMLEditRules.h
@@ -130,6 +130,7 @@ protected:
nsresult WillLoadHTML(nsISelection *aSelection, PRBool *aCancel);
nsresult WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled);
nsresult DidInsertBreak(nsISelection *aSelection, nsresult aResult);
+ nsresult SplitMailCites(nsISelection *aSelection, PRBool aPlaintext, PRBool *aHandled);
nsresult WillDeleteSelection(nsISelection *aSelection, nsIEditor::EDirection aAction,
PRBool *aCancel, PRBool *aHandled);
nsresult JoinBlocks(nsISelection *aSelection, nsCOMPtr *aLeftBlock,
diff --git a/editor/libeditor/text/nsPlaintextEditor.cpp b/editor/libeditor/text/nsPlaintextEditor.cpp
index 82f160130970..7cc1c64aa5a9 100644
--- a/editor/libeditor/text/nsPlaintextEditor.cpp
+++ b/editor/libeditor/text/nsPlaintextEditor.cpp
@@ -1685,7 +1685,8 @@ nsPlaintextEditor::InsertAsQuotation(const nsAString& aQuotedText,
// 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'));
+ if (!aQuotedText.IsEmpty() && (aQuotedText.Last() != PRUnichar('\n')))
+ quotedStuff.Append(PRUnichar('\n'));
nsCOMPtr preNode;
// get selection