From 9a35a75ae33f3e37b8becf118bb656543216c586 Mon Sep 17 00:00:00 2001 From: "jfrancis%netscape.com" Date: Tue, 17 Apr 2001 10:15:05 +0000 Subject: [PATCH] fixes for bugs: 75618 CR line breaks not recognized when inserting data in a plain 76258 IsEditable() needs to be smarter 72968 browser crashes when doing REDO after doing some cut/paste i 55224 switching from HTML Source mode to Normal causes dataloss 71355 style buttons do not work from 2nd cell onwards inside table 71362 empty tables inside (otherwise) empty list item disappears w 74655 40% of reply time in mailcompose spent converting linefeeds r=fm; sr=kin git-svn-id: svn://10.0.0.236/trunk@92547 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/editor/base/nsEditor.cpp | 5 +- mozilla/editor/base/nsHTMLDataTransfer.cpp | 5 +- mozilla/editor/base/nsHTMLEditRules.cpp | 94 ++++++++++--------- mozilla/editor/base/nsHTMLEditor.cpp | 39 +++++++- mozilla/editor/base/nsHTMLEditor.h | 2 + mozilla/editor/base/nsHTMLEditorStyle.cpp | 7 +- mozilla/editor/libeditor/base/nsEditor.cpp | 5 +- .../libeditor/html/nsHTMLDataTransfer.cpp | 5 +- .../editor/libeditor/html/nsHTMLEditRules.cpp | 94 ++++++++++--------- .../editor/libeditor/html/nsHTMLEditor.cpp | 39 +++++++- mozilla/editor/libeditor/html/nsHTMLEditor.h | 2 + .../libeditor/html/nsHTMLEditorStyle.cpp | 7 +- 12 files changed, 202 insertions(+), 102 deletions(-) diff --git a/mozilla/editor/base/nsEditor.cpp b/mozilla/editor/base/nsEditor.cpp index b015fd40575..c7d62a08449 100644 --- a/mozilla/editor/base/nsEditor.cpp +++ b/mozilla/editor/base/nsEditor.cpp @@ -3494,7 +3494,8 @@ nsEditor::IsEditable(nsIDOMNode *aNode) if (!shell) return PR_FALSE; if (IsMozEditorBogusNode(aNode)) return PR_FALSE; - + +/* THIS DOESN'T WORK! // it's not the bogus node, so see if it is an irrelevant text node if (PR_TRUE==IsTextNode(aNode)) { @@ -3521,7 +3522,7 @@ nsEditor::IsEditable(nsIDOMNode *aNode) return PR_FALSE; } } - +*/ // we got this far, so see if it has a frame. If so, we'll edit it. nsIFrame *resultFrame; nsCOMPtrcontent; diff --git a/mozilla/editor/base/nsHTMLDataTransfer.cpp b/mozilla/editor/base/nsHTMLDataTransfer.cpp index 76798a07f1c..5cfcb6a55f1 100644 --- a/mozilla/editor/base/nsHTMLDataTransfer.cpp +++ b/mozilla/editor/base/nsHTMLDataTransfer.cpp @@ -186,6 +186,8 @@ nsresult nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsAReadableString & { if (!mRules) return NS_ERROR_NOT_INITIALIZED; +/* all this is unneeded: parser handles this for us + // First, make sure there are no return chars in the document. // Bad things happen if you insert returns (instead of dom newlines, \n) // into an editor document. @@ -198,6 +200,7 @@ nsresult nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsAReadableString & // Mac linebreaks: Map any remaining CR to LF: inputString.ReplaceSubstring(NS_ConvertASCIItoUCS2("\r"), NS_ConvertASCIItoUCS2("\n")); +*/ // force IME commit; set up rules sniffing and batching ForceCompositionEnd(); @@ -223,7 +226,7 @@ nsresult nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsAReadableString & // create a dom document fragment that represents the structure to paste nsCOMPtr fragmentAsNode; PRInt32 rangeStartHint, rangeEndHint; - res = CreateDOMFragmentFromPaste(nsrange, inputString, aContextStr, aInfoStr, + res = CreateDOMFragmentFromPaste(nsrange, aInputString, aContextStr, aInfoStr, address_of(fragmentAsNode), &rangeStartHint, &rangeEndHint); NS_ENSURE_SUCCESS(res, res); diff --git a/mozilla/editor/base/nsHTMLEditRules.cpp b/mozilla/editor/base/nsHTMLEditRules.cpp index 9ddf6e35da1..7ca7d9d081a 100644 --- a/mozilla/editor/base/nsHTMLEditRules.cpp +++ b/mozilla/editor/base/nsHTMLEditRules.cpp @@ -883,15 +883,16 @@ nsHTMLEditRules::WillInsert(nsISelection *aSelection, PRBool *aCancel) else block1 = mHTMLEditor->GetBlockNodeParent(selNode); block2 = mHTMLEditor->GetBlockNodeParent(priorNode); - if (block1 != block2) return NS_OK; - - // if we are here then the selection is right after a mozBR - // that is in the same block as the selection. We need to move - // the selection start to be before the mozBR. - res = nsEditor::GetNodeLocation(priorNode, address_of(selNode), &selOffset); - if (NS_FAILED(res)) return res; - res = aSelection->Collapse(selNode,selOffset); - if (NS_FAILED(res)) return res; + if (block1 == block2) + { + // if we are here then the selection is right after a mozBR + // that is in the same block as the selection. We need to move + // the selection start to be before the mozBR. + res = nsEditor::GetNodeLocation(priorNode, address_of(selNode), &selOffset); + if (NS_FAILED(res)) return res; + res = aSelection->Collapse(selNode,selOffset); + if (NS_FAILED(res)) return res; + } } // we need to get the doc @@ -901,8 +902,7 @@ nsHTMLEditRules::WillInsert(nsISelection *aSelection, PRBool *aCancel) if (!doc) return NS_ERROR_NULL_POINTER; // for every property that is set, insert a new inline style node - res = CreateStyleForInsertText(aSelection, doc); - return res; + return CreateStyleForInsertText(aSelection, doc); } nsresult @@ -998,7 +998,7 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction, // dont spaz my selection in subtransactions nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor); nsSubsumeStr subStr; - const nsPromiseFlatString &tString = PromiseFlatString(*inString);////MJUDGE SCC NEED HELP + nsAutoString tString(*inString); const PRUnichar *unicodeBuf = tString.get(); nsCOMPtr unused; PRInt32 pos = 0; @@ -1008,21 +1008,13 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction, // it is to search for both tabs and newlines. if (isPRE) { - nsAutoString newlineChar(NS_LITERAL_STRING("\n")); + char newlineChar = '\n'; while (unicodeBuf && (pos != -1) && (pos < (PRInt32)(*inString).Length())) { PRInt32 oldPos = pos; PRInt32 subStrLen; - pos = -1; - nsReadingIterator beginFindIter, endFindIter, beginIter; - inString->BeginReading(beginIter); - beginFindIter = beginIter; - inString->EndReading(endFindIter); - beginFindIter.advance(oldPos); - if (FindInReadable(newlineChar,beginFindIter,endFindIter)) - { - pos = Distance(beginIter,beginFindIter); - } + pos = tString.FindChar(newlineChar, PR_FALSE, oldPos); + if (pos != -1) { subStrLen = pos - oldPos; @@ -1032,8 +1024,8 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction, } else { - subStrLen = (*inString).Length() - oldPos; - pos = (*inString).Length(); + subStrLen = tString.Length() - oldPos; + pos = tString.Length(); } subStr.Subsume((PRUnichar*)&unicodeBuf[oldPos], PR_FALSE, subStrLen); @@ -1053,22 +1045,13 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction, } else { - nsAutoString specialChars; - specialChars = NS_LITERAL_STRING("\t\n"); + char specialChars[] = {'\t','\n',0}; nsAutoString tabString; tabString.AssignWithConversion(" "); - while (unicodeBuf && (pos != -1) && (pos < (PRInt32)(*inString).Length())) + while (unicodeBuf && (pos != -1) && (pos < (PRInt32)inString->Length())) { PRInt32 oldPos = pos; PRInt32 subStrLen; - nsReadingIterator beginFindIter,endFindIter; - (*inString).BeginReading(beginFindIter); - beginFindIter.advance(oldPos); - (*inString).EndReading(endFindIter); - nsReadingIterator distanceIter; - (*inString).BeginReading(distanceIter); - pos = -1; - if (FindInReadable((const nsAString &)specialChars,beginFindIter,endFindIter)) - pos = Distance(distanceIter,beginFindIter); + pos = tString.FindCharInSet(specialChars, oldPos); if (pos != -1) { @@ -1079,8 +1062,8 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction, } else { - subStrLen = (*inString).Length() - oldPos; - pos = (*inString).Length(); + subStrLen = tString.Length() - oldPos; + pos = tString.Length(); } subStr.Subsume((PRUnichar*)&unicodeBuf[oldPos], PR_FALSE, subStrLen); @@ -1435,7 +1418,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection, res = mHTMLEditor->GetPriorHTMLNode(startNode, address_of(priorNode)); if (NS_FAILED(res)) return res; // are they in same block? - if (mHTMLEditor->HasSameBlockNodeParent(startNode, priorNode)) + if (priorNode && mHTMLEditor->HasSameBlockNodeParent(startNode, priorNode)) { // are they same type? if (mHTMLEditor->IsTextNode(priorNode)) @@ -1546,7 +1529,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection, res = mHTMLEditor->GetNextHTMLNode(startNode, address_of(nextNode)); if (NS_FAILED(res)) return res; // are they in same block? - if (mHTMLEditor->HasSameBlockNodeParent(startNode, nextNode)) + if (nextNode && mHTMLEditor->HasSameBlockNodeParent(startNode, nextNode)) { // are they same type? if ( mHTMLEditor->IsTextNode(nextNode) ) @@ -1703,7 +1686,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection, { nsCOMPtr brNode; res = mHTMLEditor->GetPriorHTMLNode(nodeToDelete, address_of(brNode)); - if (nsTextEditUtils::IsBreak(brNode)) + if (brNode && nsTextEditUtils::IsBreak(brNode)) { // is brNode also a descendant of same block? nsCOMPtr block, brBlock; @@ -5273,6 +5256,33 @@ nsHTMLEditRules::RemoveEmptyNodes() PRBool bIsEmptyNode; res = mHTMLEditor->IsEmptyNode(node, &bIsEmptyNode, PR_FALSE, PR_TRUE); if (NS_FAILED(res)) return res; + + // only consider certain nodes to be empty for purposes of removal + if (!( + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("b")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("i")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("u")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("tt")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("s")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("strike")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("big")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("small")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("blink")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("sub")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("sup")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("font")) || + nsHTMLEditUtils::IsList(node) || + nsHTMLEditUtils::IsParagraph(node) || + nsHTMLEditUtils::IsHeader(node) || + nsHTMLEditUtils::IsListItem(node) || + nsHTMLEditUtils::IsBlockquote(node)|| + nsHTMLEditUtils::IsDiv(node) || + nsHTMLEditUtils::IsPre(node) || + nsHTMLEditUtils::IsAddress(node) ) ) + { + bIsEmptyNode = PR_FALSE; + } + if (bIsEmptyNode && !nsTextEditUtils::IsBody(node)) { if (nsHTMLEditUtils::IsParagraph(node) || diff --git a/mozilla/editor/base/nsHTMLEditor.cpp b/mozilla/editor/base/nsHTMLEditor.cpp index 530b415c3bf..8578f2e6916 100644 --- a/mozilla/editor/base/nsHTMLEditor.cpp +++ b/mozilla/editor/base/nsHTMLEditor.cpp @@ -603,6 +603,14 @@ nsHTMLEditor::NodeIsBlock(nsIDOMNode *aNode, PRBool *aIsBlock) return NodeIsBlockStatic(aNode, aIsBlock); } +PRBool +nsHTMLEditor::IsBlockNode(nsIDOMNode *aNode) +{ + PRBool isBlock; + NodeIsBlockStatic(aNode, &isBlock); + return isBlock; +} + // Non-static version for the nsIEditor interface and JavaScript NS_IMETHODIMP nsHTMLEditor::SetDocumentTitle(const nsAReadableString &aTitle) @@ -4451,7 +4459,6 @@ nsHTMLEditor::IsEmptyNode( nsIDOMNode *aNode, // want to treat them as such. Also, don't call ListItems or table // cells empty if caller desires. if (!IsContainer(aNode) || nsHTMLEditUtils::IsAnchor(aNode) || - nsHTMLEditUtils::IsTextarea(aNode) || nsHTMLEditUtils::IsMap(aNode) || (aListOrCellNotEmpty && nsHTMLEditUtils::IsListItem(aNode)) || (aListOrCellNotEmpty && nsHTMLEditUtils::IsTableCell(aNode)) ) { @@ -4459,6 +4466,15 @@ nsHTMLEditor::IsEmptyNode( nsIDOMNode *aNode, return NS_OK; } + // are we checking a block node? + PRBool isBlock = IsBlockNode(aNode); + // if so, we allow one br without violating emptiness + PRBool seenBR = PR_FALSE; + + // need this for later + PRBool isListItemOrCell = + nsHTMLEditUtils::IsListItem(aNode) || nsHTMLEditUtils::IsTableCell(aNode); + // iterate over node. if no children, or all children are either // empty text nodes or non-editable, then node qualifies as empty nsCOMPtr iter; @@ -4522,9 +4538,28 @@ 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 && nsTextEditUtils::IsMozBR(node))) + if ((aMozBRDoesntCount && nsTextEditUtils::IsMozBR(node))) + { + // do nothing + } + else if (isBlock && !seenBR && nsTextEditUtils::IsBreak(node)) + { + // the first br in a block doesn't count + seenBR = PR_TRUE; + } + else { // is it an empty node of some sort? + // note: list items or table cells are not considered empty + // if they contain other lists or tables + if (isListItemOrCell) + { + if (nsHTMLEditUtils::IsList(node) || nsHTMLEditUtils::IsTable(node)) + { + *outIsEmptyNode = PR_FALSE; + break; + } + } PRBool isEmptyNode; res = IsEmptyNode(node, &isEmptyNode, aMozBRDoesntCount, aListOrCellNotEmpty); if (NS_FAILED(res)) return res; diff --git a/mozilla/editor/base/nsHTMLEditor.h b/mozilla/editor/base/nsHTMLEditor.h index 5434e6a96bd..9ce6a66ed46 100644 --- a/mozilla/editor/base/nsHTMLEditor.h +++ b/mozilla/editor/base/nsHTMLEditor.h @@ -383,6 +383,8 @@ public: PRBool aMozBRDoesntCount = PR_FALSE, PRBool aListOrCellNotEmpty = PR_FALSE, PRBool aSafeToAskFrames = PR_FALSE); + + PRBool IsBlockNode(nsIDOMNode *aNode); protected: diff --git a/mozilla/editor/base/nsHTMLEditorStyle.cpp b/mozilla/editor/base/nsHTMLEditorStyle.cpp index fd4f1f45894..a0389043635 100644 --- a/mozilla/editor/base/nsHTMLEditorStyle.cpp +++ b/mozilla/editor/base/nsHTMLEditorStyle.cpp @@ -486,7 +486,8 @@ nsresult nsHTMLEditor::SplitStyleAbovePoint(nsCOMPtr *aNode, // split any matching style nodes above the node/offset nsCOMPtr parent, tmp = *aNode; PRInt32 offset; - while (tmp && !nsTextEditUtils::IsBody(tmp)) + + while (tmp && !IsBlockNode(tmp)) { if ( (aProperty && NodeIsType(tmp, aProperty)) || // node is the correct inline prop (aProperty == nsIEditProperty::href && nsHTMLEditUtils::IsLink(tmp)) || // node is href - test if really content; diff --git a/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp b/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp index 76798a07f1c..5cfcb6a55f1 100644 --- a/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp @@ -186,6 +186,8 @@ nsresult nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsAReadableString & { if (!mRules) return NS_ERROR_NOT_INITIALIZED; +/* all this is unneeded: parser handles this for us + // First, make sure there are no return chars in the document. // Bad things happen if you insert returns (instead of dom newlines, \n) // into an editor document. @@ -198,6 +200,7 @@ nsresult nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsAReadableString & // Mac linebreaks: Map any remaining CR to LF: inputString.ReplaceSubstring(NS_ConvertASCIItoUCS2("\r"), NS_ConvertASCIItoUCS2("\n")); +*/ // force IME commit; set up rules sniffing and batching ForceCompositionEnd(); @@ -223,7 +226,7 @@ nsresult nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsAReadableString & // create a dom document fragment that represents the structure to paste nsCOMPtr fragmentAsNode; PRInt32 rangeStartHint, rangeEndHint; - res = CreateDOMFragmentFromPaste(nsrange, inputString, aContextStr, aInfoStr, + res = CreateDOMFragmentFromPaste(nsrange, aInputString, aContextStr, aInfoStr, address_of(fragmentAsNode), &rangeStartHint, &rangeEndHint); NS_ENSURE_SUCCESS(res, res); diff --git a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp index 9ddf6e35da1..7ca7d9d081a 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp @@ -883,15 +883,16 @@ nsHTMLEditRules::WillInsert(nsISelection *aSelection, PRBool *aCancel) else block1 = mHTMLEditor->GetBlockNodeParent(selNode); block2 = mHTMLEditor->GetBlockNodeParent(priorNode); - if (block1 != block2) return NS_OK; - - // if we are here then the selection is right after a mozBR - // that is in the same block as the selection. We need to move - // the selection start to be before the mozBR. - res = nsEditor::GetNodeLocation(priorNode, address_of(selNode), &selOffset); - if (NS_FAILED(res)) return res; - res = aSelection->Collapse(selNode,selOffset); - if (NS_FAILED(res)) return res; + if (block1 == block2) + { + // if we are here then the selection is right after a mozBR + // that is in the same block as the selection. We need to move + // the selection start to be before the mozBR. + res = nsEditor::GetNodeLocation(priorNode, address_of(selNode), &selOffset); + if (NS_FAILED(res)) return res; + res = aSelection->Collapse(selNode,selOffset); + if (NS_FAILED(res)) return res; + } } // we need to get the doc @@ -901,8 +902,7 @@ nsHTMLEditRules::WillInsert(nsISelection *aSelection, PRBool *aCancel) if (!doc) return NS_ERROR_NULL_POINTER; // for every property that is set, insert a new inline style node - res = CreateStyleForInsertText(aSelection, doc); - return res; + return CreateStyleForInsertText(aSelection, doc); } nsresult @@ -998,7 +998,7 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction, // dont spaz my selection in subtransactions nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor); nsSubsumeStr subStr; - const nsPromiseFlatString &tString = PromiseFlatString(*inString);////MJUDGE SCC NEED HELP + nsAutoString tString(*inString); const PRUnichar *unicodeBuf = tString.get(); nsCOMPtr unused; PRInt32 pos = 0; @@ -1008,21 +1008,13 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction, // it is to search for both tabs and newlines. if (isPRE) { - nsAutoString newlineChar(NS_LITERAL_STRING("\n")); + char newlineChar = '\n'; while (unicodeBuf && (pos != -1) && (pos < (PRInt32)(*inString).Length())) { PRInt32 oldPos = pos; PRInt32 subStrLen; - pos = -1; - nsReadingIterator beginFindIter, endFindIter, beginIter; - inString->BeginReading(beginIter); - beginFindIter = beginIter; - inString->EndReading(endFindIter); - beginFindIter.advance(oldPos); - if (FindInReadable(newlineChar,beginFindIter,endFindIter)) - { - pos = Distance(beginIter,beginFindIter); - } + pos = tString.FindChar(newlineChar, PR_FALSE, oldPos); + if (pos != -1) { subStrLen = pos - oldPos; @@ -1032,8 +1024,8 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction, } else { - subStrLen = (*inString).Length() - oldPos; - pos = (*inString).Length(); + subStrLen = tString.Length() - oldPos; + pos = tString.Length(); } subStr.Subsume((PRUnichar*)&unicodeBuf[oldPos], PR_FALSE, subStrLen); @@ -1053,22 +1045,13 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction, } else { - nsAutoString specialChars; - specialChars = NS_LITERAL_STRING("\t\n"); + char specialChars[] = {'\t','\n',0}; nsAutoString tabString; tabString.AssignWithConversion(" "); - while (unicodeBuf && (pos != -1) && (pos < (PRInt32)(*inString).Length())) + while (unicodeBuf && (pos != -1) && (pos < (PRInt32)inString->Length())) { PRInt32 oldPos = pos; PRInt32 subStrLen; - nsReadingIterator beginFindIter,endFindIter; - (*inString).BeginReading(beginFindIter); - beginFindIter.advance(oldPos); - (*inString).EndReading(endFindIter); - nsReadingIterator distanceIter; - (*inString).BeginReading(distanceIter); - pos = -1; - if (FindInReadable((const nsAString &)specialChars,beginFindIter,endFindIter)) - pos = Distance(distanceIter,beginFindIter); + pos = tString.FindCharInSet(specialChars, oldPos); if (pos != -1) { @@ -1079,8 +1062,8 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction, } else { - subStrLen = (*inString).Length() - oldPos; - pos = (*inString).Length(); + subStrLen = tString.Length() - oldPos; + pos = tString.Length(); } subStr.Subsume((PRUnichar*)&unicodeBuf[oldPos], PR_FALSE, subStrLen); @@ -1435,7 +1418,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection, res = mHTMLEditor->GetPriorHTMLNode(startNode, address_of(priorNode)); if (NS_FAILED(res)) return res; // are they in same block? - if (mHTMLEditor->HasSameBlockNodeParent(startNode, priorNode)) + if (priorNode && mHTMLEditor->HasSameBlockNodeParent(startNode, priorNode)) { // are they same type? if (mHTMLEditor->IsTextNode(priorNode)) @@ -1546,7 +1529,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection, res = mHTMLEditor->GetNextHTMLNode(startNode, address_of(nextNode)); if (NS_FAILED(res)) return res; // are they in same block? - if (mHTMLEditor->HasSameBlockNodeParent(startNode, nextNode)) + if (nextNode && mHTMLEditor->HasSameBlockNodeParent(startNode, nextNode)) { // are they same type? if ( mHTMLEditor->IsTextNode(nextNode) ) @@ -1703,7 +1686,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection, { nsCOMPtr brNode; res = mHTMLEditor->GetPriorHTMLNode(nodeToDelete, address_of(brNode)); - if (nsTextEditUtils::IsBreak(brNode)) + if (brNode && nsTextEditUtils::IsBreak(brNode)) { // is brNode also a descendant of same block? nsCOMPtr block, brBlock; @@ -5273,6 +5256,33 @@ nsHTMLEditRules::RemoveEmptyNodes() PRBool bIsEmptyNode; res = mHTMLEditor->IsEmptyNode(node, &bIsEmptyNode, PR_FALSE, PR_TRUE); if (NS_FAILED(res)) return res; + + // only consider certain nodes to be empty for purposes of removal + if (!( + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("b")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("i")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("u")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("tt")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("s")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("strike")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("big")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("small")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("blink")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("sub")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("sup")) || + nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("font")) || + nsHTMLEditUtils::IsList(node) || + nsHTMLEditUtils::IsParagraph(node) || + nsHTMLEditUtils::IsHeader(node) || + nsHTMLEditUtils::IsListItem(node) || + nsHTMLEditUtils::IsBlockquote(node)|| + nsHTMLEditUtils::IsDiv(node) || + nsHTMLEditUtils::IsPre(node) || + nsHTMLEditUtils::IsAddress(node) ) ) + { + bIsEmptyNode = PR_FALSE; + } + if (bIsEmptyNode && !nsTextEditUtils::IsBody(node)) { if (nsHTMLEditUtils::IsParagraph(node) || diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp index 530b415c3bf..8578f2e6916 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp @@ -603,6 +603,14 @@ nsHTMLEditor::NodeIsBlock(nsIDOMNode *aNode, PRBool *aIsBlock) return NodeIsBlockStatic(aNode, aIsBlock); } +PRBool +nsHTMLEditor::IsBlockNode(nsIDOMNode *aNode) +{ + PRBool isBlock; + NodeIsBlockStatic(aNode, &isBlock); + return isBlock; +} + // Non-static version for the nsIEditor interface and JavaScript NS_IMETHODIMP nsHTMLEditor::SetDocumentTitle(const nsAReadableString &aTitle) @@ -4451,7 +4459,6 @@ nsHTMLEditor::IsEmptyNode( nsIDOMNode *aNode, // want to treat them as such. Also, don't call ListItems or table // cells empty if caller desires. if (!IsContainer(aNode) || nsHTMLEditUtils::IsAnchor(aNode) || - nsHTMLEditUtils::IsTextarea(aNode) || nsHTMLEditUtils::IsMap(aNode) || (aListOrCellNotEmpty && nsHTMLEditUtils::IsListItem(aNode)) || (aListOrCellNotEmpty && nsHTMLEditUtils::IsTableCell(aNode)) ) { @@ -4459,6 +4466,15 @@ nsHTMLEditor::IsEmptyNode( nsIDOMNode *aNode, return NS_OK; } + // are we checking a block node? + PRBool isBlock = IsBlockNode(aNode); + // if so, we allow one br without violating emptiness + PRBool seenBR = PR_FALSE; + + // need this for later + PRBool isListItemOrCell = + nsHTMLEditUtils::IsListItem(aNode) || nsHTMLEditUtils::IsTableCell(aNode); + // iterate over node. if no children, or all children are either // empty text nodes or non-editable, then node qualifies as empty nsCOMPtr iter; @@ -4522,9 +4538,28 @@ 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 && nsTextEditUtils::IsMozBR(node))) + if ((aMozBRDoesntCount && nsTextEditUtils::IsMozBR(node))) + { + // do nothing + } + else if (isBlock && !seenBR && nsTextEditUtils::IsBreak(node)) + { + // the first br in a block doesn't count + seenBR = PR_TRUE; + } + else { // is it an empty node of some sort? + // note: list items or table cells are not considered empty + // if they contain other lists or tables + if (isListItemOrCell) + { + if (nsHTMLEditUtils::IsList(node) || nsHTMLEditUtils::IsTable(node)) + { + *outIsEmptyNode = PR_FALSE; + break; + } + } PRBool isEmptyNode; res = IsEmptyNode(node, &isEmptyNode, aMozBRDoesntCount, aListOrCellNotEmpty); if (NS_FAILED(res)) return res; diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.h b/mozilla/editor/libeditor/html/nsHTMLEditor.h index 5434e6a96bd..9ce6a66ed46 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.h +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.h @@ -383,6 +383,8 @@ public: PRBool aMozBRDoesntCount = PR_FALSE, PRBool aListOrCellNotEmpty = PR_FALSE, PRBool aSafeToAskFrames = PR_FALSE); + + PRBool IsBlockNode(nsIDOMNode *aNode); protected: diff --git a/mozilla/editor/libeditor/html/nsHTMLEditorStyle.cpp b/mozilla/editor/libeditor/html/nsHTMLEditorStyle.cpp index fd4f1f45894..a0389043635 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditorStyle.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditorStyle.cpp @@ -486,7 +486,8 @@ nsresult nsHTMLEditor::SplitStyleAbovePoint(nsCOMPtr *aNode, // split any matching style nodes above the node/offset nsCOMPtr parent, tmp = *aNode; PRInt32 offset; - while (tmp && !nsTextEditUtils::IsBody(tmp)) + + while (tmp && !IsBlockNode(tmp)) { if ( (aProperty && NodeIsType(tmp, aProperty)) || // node is the correct inline prop (aProperty == nsIEditProperty::href && nsHTMLEditUtils::IsLink(tmp)) || // node is href - test if really