curNode, curParent, curBlock, newBlock;
PRInt32 offset;
PRUint32 listCount;
- PRBool bNoParent = PR_FALSE;
-
- // we special case an empty tag name to mean "remove block parents".
- // This is used for the "normal" paragraph style in mail-compose
nsString tString(*aBlockTag);////MJUDGE SCC NEED HELP
- if (tString.IsEmpty() ||
- !Compare(tString,NS_LITERAL_STRING("normal"),nsCaseInsensitiveStringComparator()))
- bNoParent = PR_TRUE;
-
+
arrayOfNodes->Count(&listCount);
PRUint32 i;
@@ -4810,13 +5084,13 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsAReadab
curNodeTag.ToLowerCase();
// is it already the right kind of block?
- if (!bNoParent && curNodeTag == *aBlockTag)
+ if (curNodeTag == *aBlockTag)
{
curBlock = 0; // forget any previous block used for previous inline nodes
continue; // do nothing to this block
}
- // if curNode is a mozdiv, p, header, address, or pre, replace
+ // if curNode is a address, p, header, address, or pre, replace
// it with a new block of correct type.
// xxx floppy moose: pre cant hold everything the others can
if (nsHTMLEditUtils::IsMozDiv(curNode) ||
@@ -4831,17 +5105,7 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsAReadab
(curNodeTag.EqualsWithConversion("address")))
{
curBlock = 0; // forget any previous block used for previous inline nodes
- if (bNoParent)
- {
- // make sure we have a normal br at end of block
- res = AddTerminatingBR(curNode);
- if (NS_FAILED(res)) return res;
- res = mHTMLEditor->RemoveContainer(curNode);
- }
- else
- {
- res = mHTMLEditor->ReplaceContainer(curNode, address_of(newBlock), *aBlockTag);
- }
+ res = mHTMLEditor->ReplaceContainer(curNode, address_of(newBlock), *aBlockTag);
if (NS_FAILED(res)) return res;
}
else if ((curNodeTag.EqualsWithConversion("table")) ||
@@ -4850,9 +5114,10 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsAReadab
(curNodeTag.EqualsWithConversion("td")) ||
(curNodeTag.EqualsWithConversion("ol")) ||
(curNodeTag.EqualsWithConversion("ul")) ||
+ (curNodeTag.EqualsWithConversion("dl")) ||
(curNodeTag.EqualsWithConversion("li")) ||
(curNodeTag.EqualsWithConversion("blockquote")) ||
- (curNodeTag.EqualsWithConversion("div"))) // div's other than mozdivs
+ (curNodeTag.EqualsWithConversion("div")))
{
curBlock = 0; // forget any previous block used for previous inline nodes
// recursion time
@@ -4867,11 +5132,8 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsAReadab
else if (curNodeTag.EqualsWithConversion("br"))
{
curBlock = 0; // forget any previous block used for previous inline nodes
- if (!bNoParent)
- {
- res = mHTMLEditor->DeleteNode(curNode);
- if (NS_FAILED(res)) return res;
- }
+ res = mHTMLEditor->DeleteNode(curNode);
+ if (NS_FAILED(res)) return res;
}
@@ -4882,7 +5144,7 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsAReadab
// arrayOfNodes is contructed, but some additional logic should
// be added here if that should change
- else if (IsInlineNode(curNode) && !bNoParent)
+ else if (IsInlineNode(curNode))
{
// if curNode is a non editable, drop it if we are going to
if (!Compare(tString,NS_LITERAL_STRING("pre"),nsCaseInsensitiveStringComparator())
@@ -4958,43 +5220,6 @@ nsHTMLEditRules::SplitAsNeeded(const nsAReadableString *aTag,
return res;
}
-///////////////////////////////////////////////////////////////////////////
-// AddTerminatingBR: place an ordinary br node at the end of aBlock,
-// if it doens't already have one. If it has a moz-BR,
-// simply convertit to a normal br.
-nsresult
-nsHTMLEditRules::AddTerminatingBR(nsIDOMNode *aBlock)
-{
- if (!aBlock) return NS_ERROR_NULL_POINTER;
- nsCOMPtr last;
- nsresult res = mHTMLEditor->GetLastEditableLeaf(aBlock, address_of(last));
- if (last && nsTextEditUtils::IsBreak(last))
- {
- if (nsTextEditUtils::IsMozBR(last))
- {
- // need to convert a br
- nsCOMPtr elem = do_QueryInterface(last);
- res = mHTMLEditor->RemoveAttribute(elem, NS_ConvertASCIItoUCS2("type"));
- if (NS_FAILED(res)) return res;
- }
- else // we have what we want, we're done
- {
- return res;
- }
- }
- else // need to add a br
- {
- PRUint32 len;
- nsCOMPtr brNode;
- res = mHTMLEditor->GetLengthOfDOMNode(aBlock, len);
- if (NS_FAILED(res)) return res;
- res = mHTMLEditor->CreateBR(aBlock, len, address_of(brNode));
- if (NS_FAILED(res)) return res;
- }
- return res;
-}
-
-
///////////////////////////////////////////////////////////////////////////
// JoinNodesSmart: join two nodes, doing whatever makes sense for their
// children (which often means joining them, too).
@@ -5744,9 +5969,7 @@ nsHTMLEditRules::PopListItem(nsIDOMNode *aListItem, PRBool *aOutOfList)
if (!nsHTMLEditUtils::IsList(curParPar)
&& nsHTMLEditUtils::IsListItem(curNode))
{
- res = AddTerminatingBR(curNode);
- if (NS_FAILED(res)) return res;
- res = mHTMLEditor->RemoveContainer(curNode);
+ res = mHTMLEditor->RemoveBlockContainer(curNode);
if (NS_FAILED(res)) return res;
*aOutOfList = PR_TRUE;
}
@@ -5788,7 +6011,7 @@ nsHTMLEditRules::RemoveListStructure(nsIDOMNode *aList)
aList->GetFirstChild(getter_AddRefs(child));
}
// delete the now-empty list
- res = mHTMLEditor->DeleteNode(aList);
+ res = mHTMLEditor->RemoveBlockContainer(aList);
if (NS_FAILED(res)) return res;
return res;
@@ -6128,12 +6351,3 @@ nsHTMLEditRules::DidDeleteSelection(nsISelection *aSelection)
{
return NS_OK;
}
-
-
-
-
-
-
-
-
-
diff --git a/mozilla/editor/base/nsHTMLEditRules.h b/mozilla/editor/base/nsHTMLEditRules.h
index 8a499f5c4f3..4a770413e47 100644
--- a/mozilla/editor/base/nsHTMLEditRules.h
+++ b/mozilla/editor/base/nsHTMLEditRules.h
@@ -122,6 +122,9 @@ protected:
nsresult ReturnInParagraph(nsISelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset, PRBool *aCancel, PRBool *aHandled);
nsresult ReturnInListItem(nsISelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset);
nsresult AfterEditInner(PRInt32 action, nsIEditor::EDirection aDirection);
+ nsresult RemovePartOfBlock(nsIDOMNode *curBlockQuote,
+ nsIDOMNode *firstBQChild,
+ nsIDOMNode *lastBQChild);
nsresult ConvertListType(nsIDOMNode *aList, nsCOMPtr *outList, const nsAReadableString& aListType, const nsAReadableString& aItemType);
nsresult CreateStyleForInsertText(nsISelection *aSelection, nsIDOMDocument *aDoc);
nsresult IsEmptyBlock(nsIDOMNode *aNode,
@@ -155,12 +158,14 @@ protected:
nsresult GetListActionNodes(nsCOMPtr *outArrayOfNodes, PRBool aEntireList, PRBool aDontTouchContent=PR_FALSE);
nsresult GetDefinitionListItemTypes(nsIDOMNode *aNode, PRBool &aDT, PRBool &aDD);
nsresult GetParagraphFormatNodes(nsCOMPtr *outArrayOfNodes, PRBool aDontTouchContent=PR_FALSE);
+ nsresult LookInsideDivBQandList(nsISupportsArray *aNodeArray);
nsresult BustUpInlinesAtRangeEndpoints(nsRangeStore &inRange);
nsresult BustUpInlinesAtBRs(nsIDOMNode *inNode,
nsCOMPtr *outArrayOfNodes);
nsCOMPtr GetHighestInlineParent(nsIDOMNode* aNode);
nsresult MakeTransitionList(nsISupportsArray *inArrayOfNodes,
nsVoidArray *inTransitionArray);
+ nsresult RemoveBlockStyle(nsISupportsArray *arrayOfNodes);
nsresult ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsAReadableString *aBlockTag);
nsresult MakeBlockquote(nsISupportsArray *arrayOfNodes);
nsresult SplitAsNeeded(const nsAReadableString *aTag, nsCOMPtr *inOutParent, PRInt32 *inOutOffset);
diff --git a/mozilla/editor/base/nsHTMLEditor.cpp b/mozilla/editor/base/nsHTMLEditor.cpp
index ec9ac4dfaf9..419f8e4637f 100644
--- a/mozilla/editor/base/nsHTMLEditor.cpp
+++ b/mozilla/editor/base/nsHTMLEditor.cpp
@@ -4095,6 +4095,103 @@ nsHTMLEditor::SetSelectionAtDocumentStart(nsISelection *aSelection)
#pragma mark -
#endif
+///////////////////////////////////////////////////////////////////////////
+// RemoveBlockContainer: remove inNode, reparenting it's children into their
+// the parent of inNode. In addition, INSERT ANY BR's NEEDED
+// TO PRESERVE IDENTITY OF REMOVED BLOCK.
+//
+nsresult
+nsHTMLEditor::RemoveBlockContainer(nsIDOMNode *inNode)
+{
+ if (!inNode)
+ return NS_ERROR_NULL_POINTER;
+ nsresult res;
+ nsCOMPtr sibling, child, unused;
+
+ // Two possibilities: the container cold be empty of editable content.
+ // If that is the case, we need to compare what is before and after inNode
+ // to determine if we need a br.
+ // Or it could not be empty, in which case we have to compare previous
+ // sibling and first child to determine if we need a leading br,
+ // and compare following sibling and last child to determine if we need a
+ // trailing br.
+
+ res = GetFirstEditableChild(inNode, address_of(child));
+ if (NS_FAILED(res)) return res;
+
+ if (child) // the case of inNode not being empty
+ {
+ // we need a br at start unless:
+ // 1) previous sibling of inNode is a block, OR
+ // 2) previous sibling of inNode is a br, OR
+ // 3) first child of inNode is a block OR
+ // 4) either is null
+
+ res = GetPriorHTMLSibling(inNode, address_of(sibling));
+ if (NS_FAILED(res)) return res;
+ if (sibling && !IsBlockNode(sibling) && !nsTextEditUtils::IsBreak(sibling))
+ {
+ res = GetFirstEditableChild(inNode, address_of(child));
+ if (NS_FAILED(res)) return res;
+ if (child && !IsBlockNode(child))
+ {
+ // insert br node
+ res = CreateBR(inNode, 0, address_of(unused));
+ if (NS_FAILED(res)) return res;
+ }
+ }
+
+ // we need a br at end unless:
+ // 1) following sibling of inNode is a block, OR
+ // 2) last child of inNode is a block, OR
+ // 3) last child of inNode is a block OR
+ // 4) either is null
+
+ res = GetNextHTMLSibling(inNode, address_of(sibling));
+ if (NS_FAILED(res)) return res;
+ if (sibling && !IsBlockNode(sibling))
+ {
+ res = GetLastEditableChild(inNode, address_of(child));
+ if (NS_FAILED(res)) return res;
+ if (child && !IsBlockNode(child) && !nsTextEditUtils::IsBreak(child))
+ {
+ // insert br node
+ PRUint32 len;
+ res = GetLengthOfDOMNode(inNode, len);
+ if (NS_FAILED(res)) return res;
+ res = CreateBR(inNode, (PRInt32)len, address_of(unused));
+ if (NS_FAILED(res)) return res;
+ }
+ }
+ }
+ else // the case of inNode being empty
+ {
+ // we need a br at start unless:
+ // 1) previous sibling of inNode is a block, OR
+ // 2) previous sibling of inNode is a br, OR
+ // 3) following sibling of inNode is a block, OR
+ // 4) following sibling of inNode is a br OR
+ // 5) either is null
+ res = GetPriorHTMLSibling(inNode, address_of(sibling));
+ if (NS_FAILED(res)) return res;
+ if (sibling && !IsBlockNode(sibling) && !nsTextEditUtils::IsBreak(sibling))
+ {
+ res = GetNextHTMLSibling(inNode, address_of(sibling));
+ if (NS_FAILED(res)) return res;
+ if (sibling && !IsBlockNode(sibling) && !nsTextEditUtils::IsBreak(sibling))
+ {
+ // insert br node
+ res = CreateBR(inNode, 0, address_of(unused));
+ if (NS_FAILED(res)) return res;
+ }
+ }
+ }
+
+ // now remove container
+ return RemoveContainer(inNode);
+}
+
+
///////////////////////////////////////////////////////////////////////////
// GetPriorHTMLSibling: returns the previous editable sibling, if there is
// one within the parent
@@ -4163,7 +4260,7 @@ nsHTMLEditor::GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr *outNo
{
res = node->GetNextSibling(getter_AddRefs(temp));
if (NS_FAILED(res)) return res;
- if (!temp) return NS_ERROR_FAILURE;
+ if (!temp) return NS_OK; // return null sibling
// if it's editable, we're done
if (IsEditable(temp)) break;
// otherwise try again
diff --git a/mozilla/editor/base/nsHTMLEditor.h b/mozilla/editor/base/nsHTMLEditor.h
index eced4d50cec..f2170f28695 100644
--- a/mozilla/editor/base/nsHTMLEditor.h
+++ b/mozilla/editor/base/nsHTMLEditor.h
@@ -642,6 +642,7 @@ protected:
PRBool HasMatchingAttributes(nsIDOMNode *aNode1,
nsIDOMNode *aNode2);
+ nsresult RemoveBlockContainer(nsIDOMNode *inNode);
nsresult GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr *outNode);
nsresult GetPriorHTMLSibling(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr *outNode);
nsresult GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr *outNode);
diff --git a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp
index ed7ee4e6156..9b43b81830a 100644
--- a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp
+++ b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp
@@ -2108,41 +2108,10 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection,
}
// if there is only one node in the array, and it is a list, div, or blockquote,
- // then look inside of it until we find what we want to make a list out of.
- if (listCount == 1)
- {
- nsCOMPtr isupports = dont_AddRef(arrayOfNodes->ElementAt(0));
- nsCOMPtr curNode( do_QueryInterface(isupports) );
-
- while (nsHTMLEditUtils::IsDiv(curNode)
- || nsHTMLEditUtils::IsList(curNode)
- || nsHTMLEditUtils::IsBlockquote(curNode))
- {
- // dive as long as there is only one child, and it is a list, div, blockquote
- PRUint32 numChildren;
- res = mHTMLEditor->CountEditableChildren(curNode, numChildren);
- if (NS_FAILED(res)) return res;
-
- if (numChildren == 1)
- {
- // keep diving
- nsCOMPtr tmpNode = nsEditor::GetChildAt(curNode, 0);
- if (nsHTMLEditUtils::IsDiv(tmpNode)
- || nsHTMLEditUtils::IsList(tmpNode)
- || nsHTMLEditUtils::IsBlockquote(tmpNode))
- {
- // check editablility XXX floppy moose
- curNode = tmpNode;
- }
- else break;
- }
- else break;
- }
- // we've found innermost list/blockquote/div:
- // replace the one node in the array with this node
- isupports = do_QueryInterface(curNode);
- arrayOfNodes->ReplaceElementAt(isupports, 0);
- }
+ // then look inside of it until we find inner list or content.
+
+ res = LookInsideDivBQandList(arrayOfNodes);
+ if (NS_FAILED(res)) return res;
// Next we detect all the transitions in the array, where a transition
// means that adjacent nodes in the array don't have the same parent.
@@ -2209,7 +2178,7 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection,
if (NS_FAILED(res)) return res;
res = ConvertListType(curNode, address_of(newBlock), *aListType, itemType);
if (NS_FAILED(res)) return res;
- res = mHTMLEditor->RemoveContainer(newBlock);
+ res = mHTMLEditor->RemoveBlockContainer(newBlock);
if (NS_FAILED(res)) return res;
}
else
@@ -2358,7 +2327,7 @@ nsHTMLEditRules::WillRemoveList(nsISelection *aSelection,
// use these ranges to contruct a list of nodes to act on.
nsCOMPtr arrayOfNodes;
- res = GetNodesForOperation(arrayOfRanges, address_of(arrayOfNodes), kMakeList);
+ res = GetListActionNodes(address_of(arrayOfNodes), PR_FALSE);
if (NS_FAILED(res)) return res;
// Remove all non-editable nodes. Leave them be.
@@ -2479,6 +2448,9 @@ nsHTMLEditRules::WillMakeBasicBlock(nsISelection *aSelection,
nsString tString(*aBlockType);
if (tString.EqualsWithConversion("blockquote"))
res = MakeBlockquote(arrayOfNodes);
+ else if (tString.EqualsWithConversion("normal") ||
+ tString.IsEmpty() )
+ res = RemoveBlockStyle(arrayOfNodes);
else
res = ApplyBlockStyle(arrayOfNodes, aBlockType);
return res;
@@ -2660,20 +2632,15 @@ nsHTMLEditRules::WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool *
if (NS_FAILED(res)) return res;
// use these ranges to contruct a list of nodes to act on.
+
nsCOMPtr arrayOfNodes;
res = GetNodesForOperation(arrayOfRanges, address_of(arrayOfNodes), kOutdent);
if (NS_FAILED(res)) return res;
- // Next we detect all the transitions in the array, where a transition
- // means that adjacent nodes in the array don't have the same parent.
-
- nsVoidArray transitionList;
- res = MakeTransitionList(arrayOfNodes, &transitionList);
- if (NS_FAILED(res)) return res;
-
// Ok, now go through all the nodes and remove a level of blockquoting,
// or whatever is appropriate. Wohoo!
+ nsCOMPtr curBlockQuote, firstBQChild, lastBQChild;
PRUint32 listCount;
PRInt32 i;
arrayOfNodes->Count(&listCount);
@@ -2687,78 +2654,175 @@ nsHTMLEditRules::WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool *
res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
if (NS_FAILED(res)) return res;
- if (nsHTMLEditUtils::IsList(curParent)) // move node out of list
+ // is it a blockquote?
+ if (nsHTMLEditUtils::IsBlockquote(curNode))
{
- if (nsHTMLEditUtils::IsList(curNode)) // just unwrap this sublist
+ // if it is a blockquote, remove it.
+ // So we need to finish up dealng with any curBlockQuote first.
+ if (curBlockQuote)
{
- res = mHTMLEditor->RemoveContainer(curNode);
+ res = RemovePartOfBlock(curBlockQuote, firstBQChild, lastBQChild);
if (NS_FAILED(res)) return res;
+ curBlockQuote = 0; firstBQChild = 0; lastBQChild = 0;
}
- else // we are moving a list item, but not whole list
- {
- PRBool bOutOfList;
- res = PopListItem(curNode, &bOutOfList);
- if (NS_FAILED(res)) return res;
- }
- }
- else if (nsHTMLEditUtils::IsList(curNode)) // node is a list, but parent is non-list: move list items out
- {
- nsCOMPtr child;
- curNode->GetLastChild(getter_AddRefs(child));
- while (child)
- {
- if (nsHTMLEditUtils::IsListItem(child))
- {
- PRBool bOutOfList;
- res = PopListItem(child, &bOutOfList);
- if (NS_FAILED(res)) return res;
- }
- else if (nsHTMLEditUtils::IsList(child))
- {
- // We have an embedded list, so move it out from under the
- // parent list. Be sure to put it after the parent list
- // because this loop iterates backwards through the parent's
- // list of children.
-
- res = mHTMLEditor->MoveNode(child, curParent, offset + 1);
- if (NS_FAILED(res)) return res;
- }
- else
- {
- // delete any non- list items for now
- res = mHTMLEditor->DeleteNode(child);
- if (NS_FAILED(res)) return res;
- }
- curNode->GetLastChild(getter_AddRefs(child));
- }
- // delete the now-empty list
- res = mHTMLEditor->DeleteNode(curNode);
+ res = mHTMLEditor->RemoveBlockContainer(curNode);
if (NS_FAILED(res)) return res;
+ continue;
}
- else if (transitionList[i]) // not list related - look for enclosing blockquotes and remove
+ // is it a list item?
+ if (nsHTMLEditUtils::IsListItem(curNode))
{
- // look for a blockquote somewhere above us and remove it.
- // this is a hack until i think about outdent for real.
- nsCOMPtr n = curNode;
- nsCOMPtr tmp;
- while (!nsTextEditUtils::IsBody(n))
+ // if it is a list item, that means we are not outdenting whole list.
+ // So we need to finish up dealng with any curBlockQuote, and then
+ // pop this list item.
+ if (curBlockQuote)
{
- if (nsHTMLEditUtils::IsBlockquote(n))
- {
- res = AddTerminatingBR(n);
- if (NS_FAILED(res)) return res;
- mHTMLEditor->RemoveContainer(n);
- break;
- }
- n->GetParentNode(getter_AddRefs(tmp));
- n = tmp;
+ res = RemovePartOfBlock(curBlockQuote, firstBQChild, lastBQChild);
+ if (NS_FAILED(res)) return res;
+ curBlockQuote = 0; firstBQChild = 0; lastBQChild = 0;
+ }
+ PRBool bOutOfList;
+ res = PopListItem(curNode, &bOutOfList);
+ if (NS_FAILED(res)) return res;
+ continue;
+ }
+ // do we have a blockquote that we are already committed to removing?
+ if (curBlockQuote)
+ {
+ // if so, is this node a descendant?
+ if (nsHTMLEditUtils::IsDescendantOf(curNode, curBlockQuote))
+ {
+ lastBQChild = curNode;
+ continue; // then we dont need to do anything different for this node
+ }
+ else
+ {
+ // otherwise, we have progressed beyond end of curBlockQuote,
+ // so lets handle it now. We need to remove the portion of
+ // curBlockQuote that contains [firstBQChild - lastBQChild].
+ res = RemovePartOfBlock(curBlockQuote, firstBQChild, lastBQChild);
+ if (NS_FAILED(res)) return res;
+ curBlockQuote = 0; firstBQChild = 0; lastBQChild = 0;
+ // fall out and handle curNode
}
}
+
+ // are we inside a blockquote?
+ nsCOMPtr n = curNode;
+ nsCOMPtr tmp;
+ while (!nsTextEditUtils::IsBody(n))
+ {
+ n->GetParentNode(getter_AddRefs(tmp));
+ n = tmp;
+ if (nsHTMLEditUtils::IsBlockquote(n))
+ {
+ // if so, remember it, and remember first node we are taking out of it.
+ curBlockQuote = n;
+ firstBQChild = curNode;
+ lastBQChild = curNode;
+ break;
+ }
+ }
+
+ if (!curBlockQuote)
+ {
+ // could not find an enclosing blockquote for this node. handle list cases.
+ if (nsHTMLEditUtils::IsList(curParent)) // move node out of list
+ {
+ if (nsHTMLEditUtils::IsList(curNode)) // just unwrap this sublist
+ {
+ res = mHTMLEditor->RemoveBlockContainer(curNode);
+ if (NS_FAILED(res)) return res;
+ }
+ // handled list item case above
+ }
+ else if (nsHTMLEditUtils::IsList(curNode)) // node is a list, but parent is non-list: move list items out
+ {
+ nsCOMPtr child;
+ curNode->GetLastChild(getter_AddRefs(child));
+ while (child)
+ {
+ if (nsHTMLEditUtils::IsListItem(child))
+ {
+ PRBool bOutOfList;
+ res = PopListItem(child, &bOutOfList);
+ if (NS_FAILED(res)) return res;
+ }
+ else if (nsHTMLEditUtils::IsList(child))
+ {
+ // We have an embedded list, so move it out from under the
+ // parent list. Be sure to put it after the parent list
+ // because this loop iterates backwards through the parent's
+ // list of children.
+
+ res = mHTMLEditor->MoveNode(child, curParent, offset + 1);
+ if (NS_FAILED(res)) return res;
+ }
+ else
+ {
+ // delete any non- list items for now
+ res = mHTMLEditor->DeleteNode(child);
+ if (NS_FAILED(res)) return res;
+ }
+ curNode->GetLastChild(getter_AddRefs(child));
+ }
+ // delete the now-empty list
+ res = mHTMLEditor->RemoveBlockContainer(curNode);
+ if (NS_FAILED(res)) return res;
+ }
+ }
+ }
+ if (curBlockQuote)
+ {
+ // we have a blockquote we haven't finished handling
+ res = RemovePartOfBlock(curBlockQuote, firstBQChild, lastBQChild);
+ if (NS_FAILED(res)) return res;
}
return res;
}
+///////////////////////////////////////////////////////////////////////////
+// ConvertListType: convert list type and list item type.
+//
+//
+nsresult
+nsHTMLEditRules::RemovePartOfBlock(nsIDOMNode *aBlock,
+ nsIDOMNode *aStartChild,
+ nsIDOMNode *aEndChild)
+{
+ if (!aBlock || !aStartChild || !aEndChild)
+ return NS_ERROR_NULL_POINTER;
+
+ nsCOMPtr startParent, endParent, leftNode, rightNode;
+ PRInt32 startOffset, endOffset, offset;
+ nsresult res;
+
+ // get split point location
+ res = nsEditor::GetNodeLocation(aStartChild, address_of(startParent), &startOffset);
+ if (NS_FAILED(res)) return res;
+
+ // do the splits!
+ res = mHTMLEditor->SplitNodeDeep(aBlock, startParent, startOffset, &offset,
+ PR_TRUE, address_of(leftNode), address_of(rightNode));
+ if (NS_FAILED(res)) return res;
+ if (rightNode) aBlock = rightNode;
+
+ // get split point location
+ res = nsEditor::GetNodeLocation(aEndChild, address_of(endParent), &endOffset);
+ if (NS_FAILED(res)) return res;
+ endOffset++; // want to be after lastBQChild
+
+ // do the splits!
+ res = mHTMLEditor->SplitNodeDeep(aBlock, endParent, endOffset, &offset,
+ PR_TRUE, address_of(leftNode), address_of(rightNode));
+ if (NS_FAILED(res)) return res;
+ if (leftNode) aBlock = leftNode;
+
+ // get rid of part of blockquote we are outdenting
+ res = mHTMLEditor->RemoveBlockContainer(aBlock);
+ return res;
+}
///////////////////////////////////////////////////////////////////////////
// ConvertListType: convert list type and list item type.
@@ -3891,6 +3955,23 @@ nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
}
}
}
+ // outdent should look inside of divs.
+ if (inOperationType == kOutdent)
+ {
+ PRUint32 listCount;
+ (*outArrayOfNodes)->Count(&listCount);
+ for (i=(PRInt32)listCount-1; i>=0; i--)
+ {
+ isupports = dont_AddRef((*outArrayOfNodes)->ElementAt(i));
+ nsCOMPtr node( do_QueryInterface(isupports) );
+ if (nsHTMLEditUtils::IsDiv(node))
+ {
+ (*outArrayOfNodes)->RemoveElementAt(i);
+ res = GetInnerContent(node, *outArrayOfNodes, PR_FALSE, PR_FALSE);
+ if (NS_FAILED(res)) return res;
+ }
+ }
+ }
// post process the list to break up inline containers that contain br's.
@@ -4057,15 +4138,77 @@ nsHTMLEditRules::GetListActionNodes(nsCOMPtr *outArrayOfNodes,
(*outArrayOfNodes)->RemoveElementAt(i);
}
- // scan for table elements. If we find table elements other than table,
+ // scan for table elements and divs. If we find table elements other than table,
// replace it with a list of any editable non-table content.
- if (nsHTMLEditUtils::IsTableElement(testNode) && !nsHTMLEditUtils::IsTable(testNode))
+ if ( (nsHTMLEditUtils::IsTableElement(testNode) && !nsHTMLEditUtils::IsTable(testNode))
+ || nsHTMLEditUtils::IsDiv(testNode) )
{
(*outArrayOfNodes)->RemoveElementAt(i);
res = GetInnerContent(testNode, *outArrayOfNodes, PR_FALSE);
if (NS_FAILED(res)) return res;
}
}
+
+ // if there is only one node in the array, and it is a list, div, or blockquote,
+ // then look inside of it until we find inner list or content.
+ res = LookInsideDivBQandList(*outArrayOfNodes);
+ return res;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// LookInsideDivBQandList:
+//
+nsresult
+nsHTMLEditRules::LookInsideDivBQandList(nsISupportsArray *aNodeArray)
+{
+ // if there is only one node in the array, and it is a list, div, or blockquote,
+ // then look inside of it until we find inner list or content.
+ nsresult res = NS_OK;
+ PRUint32 listCount;
+ aNodeArray->Count(&listCount);
+ if (listCount == 1)
+ {
+ nsCOMPtr isupports = dont_AddRef(aNodeArray->ElementAt(0));
+ nsCOMPtr curNode( do_QueryInterface(isupports) );
+
+ while (nsHTMLEditUtils::IsDiv(curNode)
+ || nsHTMLEditUtils::IsList(curNode)
+ || nsHTMLEditUtils::IsBlockquote(curNode))
+ {
+ // dive as long as there is only one child, and it is a list, div, blockquote
+ PRUint32 numChildren;
+ res = mHTMLEditor->CountEditableChildren(curNode, numChildren);
+ if (NS_FAILED(res)) return res;
+
+ if (numChildren == 1)
+ {
+ // keep diving
+ nsCOMPtr tmpNode = nsEditor::GetChildAt(curNode, 0);
+ if (nsHTMLEditUtils::IsDiv(tmpNode)
+ || nsHTMLEditUtils::IsList(tmpNode)
+ || nsHTMLEditUtils::IsBlockquote(tmpNode))
+ {
+ // check editablility XXX floppy moose
+ curNode = tmpNode;
+ }
+ else break;
+ }
+ else break;
+ }
+ // we've found innermost list/blockquote/div:
+ // replace the one node in the array with these nodes
+ aNodeArray->RemoveElementAt(0);
+ if ((nsHTMLEditUtils::IsDiv(curNode) || nsHTMLEditUtils::IsBlockquote(curNode)))
+ {
+ res = GetInnerContent(curNode, aNodeArray, PR_FALSE, PR_FALSE);
+ }
+ else
+ {
+ nsCOMPtr isuports (do_QueryInterface(curNode));
+ res = aNodeArray->AppendElement(isuports);
+ }
+ }
return res;
}
@@ -4769,6 +4912,144 @@ nsHTMLEditRules::MakeBlockquote(nsISupportsArray *arrayOfNodes)
+///////////////////////////////////////////////////////////////////////////
+// RemoveBlockStyle: make the list nodes have no special block type.
+//
+nsresult
+nsHTMLEditRules::RemoveBlockStyle(nsISupportsArray *arrayOfNodes)
+{
+ // intent of this routine is to be used for converting to/from
+ // headers, paragraphs, pre, and address. Those blocks
+ // that pretty much just contain inline things...
+
+ if (!arrayOfNodes) return NS_ERROR_NULL_POINTER;
+ nsresult res = NS_OK;
+
+ nsCOMPtr curNode, curParent, curBlock, firstNode, lastNode;
+ PRInt32 offset;
+ PRUint32 listCount;
+
+ arrayOfNodes->Count(&listCount);
+
+ PRUint32 i;
+ for (i=0; i isupports = dont_AddRef(arrayOfNodes->ElementAt(i));
+ curNode = do_QueryInterface(isupports);
+ res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
+ if (NS_FAILED(res)) return res;
+ nsAutoString curNodeTag;
+ nsEditor::GetTagString(curNode, curNodeTag);
+ curNodeTag.ToLowerCase();
+
+ // if curNode is a address, p, header, address, or pre, remove it
+ if ((curNodeTag.EqualsWithConversion("pre")) ||
+ (curNodeTag.EqualsWithConversion("p")) ||
+ (curNodeTag.EqualsWithConversion("h1")) ||
+ (curNodeTag.EqualsWithConversion("h2")) ||
+ (curNodeTag.EqualsWithConversion("h3")) ||
+ (curNodeTag.EqualsWithConversion("h4")) ||
+ (curNodeTag.EqualsWithConversion("h5")) ||
+ (curNodeTag.EqualsWithConversion("h6")) ||
+ (curNodeTag.EqualsWithConversion("address")))
+ {
+ // process any partial progress saved
+ if (curBlock)
+ {
+ res = RemovePartOfBlock(curBlock, firstNode, lastNode);
+ if (NS_FAILED(res)) return res;
+ curBlock = 0; firstNode = 0; lastNode = 0;
+ }
+ // remove curent block
+ res = mHTMLEditor->RemoveBlockContainer(curNode);
+ if (NS_FAILED(res)) return res;
+ }
+ else if ((curNodeTag.EqualsWithConversion("table")) ||
+ (curNodeTag.EqualsWithConversion("tbody")) ||
+ (curNodeTag.EqualsWithConversion("tr")) ||
+ (curNodeTag.EqualsWithConversion("td")) ||
+ (curNodeTag.EqualsWithConversion("ol")) ||
+ (curNodeTag.EqualsWithConversion("ul")) ||
+ (curNodeTag.EqualsWithConversion("dl")) ||
+ (curNodeTag.EqualsWithConversion("li")) ||
+ (curNodeTag.EqualsWithConversion("blockquote")) ||
+ (curNodeTag.EqualsWithConversion("div")))
+ {
+ // process any partial progress saved
+ if (curBlock)
+ {
+ res = RemovePartOfBlock(curBlock, firstNode, lastNode);
+ if (NS_FAILED(res)) return res;
+ curBlock = 0; firstNode = 0; lastNode = 0;
+ }
+ // recursion time
+ nsCOMPtr childArray;
+ res = GetChildNodesForOperation(curNode, address_of(childArray));
+ if (NS_FAILED(res)) return res;
+ res = RemoveBlockStyle(childArray);
+ if (NS_FAILED(res)) return res;
+ }
+ else if (IsInlineNode(curNode))
+ {
+ if (curBlock)
+ {
+ // if so, is this node a descendant?
+ if (nsHTMLEditUtils::IsDescendantOf(curNode, curBlock))
+ {
+ lastNode = curNode;
+ continue; // then we dont need to do anything different for this node
+ }
+ else
+ {
+ // otherwise, we have progressed beyond end of curBlock,
+ // so lets handle it now. We need to remove the portion of
+ // curBlock that contains [firstNode - lastNode].
+ res = RemovePartOfBlock(curBlock, firstNode, lastNode);
+ if (NS_FAILED(res)) return res;
+ curBlock = 0; firstNode = 0; lastNode = 0;
+ // fall out and handle curNode
+ }
+ }
+ curBlock = mHTMLEditor->GetBlockNodeParent(curNode);
+ if ((curNodeTag.EqualsWithConversion("pre")) ||
+ (curNodeTag.EqualsWithConversion("p")) ||
+ (curNodeTag.EqualsWithConversion("h1")) ||
+ (curNodeTag.EqualsWithConversion("h2")) ||
+ (curNodeTag.EqualsWithConversion("h3")) ||
+ (curNodeTag.EqualsWithConversion("h4")) ||
+ (curNodeTag.EqualsWithConversion("h5")) ||
+ (curNodeTag.EqualsWithConversion("h6")) ||
+ (curNodeTag.EqualsWithConversion("address")))
+ {
+ firstNode = curNode;
+ lastNode = curNode;
+ }
+ else
+ curBlock = 0; // not a block kind that we care about.
+ }
+ else
+ { // some node that is already sans block style. skip over it and
+ // process any partial progress saved
+ if (curBlock)
+ {
+ res = RemovePartOfBlock(curBlock, firstNode, lastNode);
+ if (NS_FAILED(res)) return res;
+ curBlock = 0; firstNode = 0; lastNode = 0;
+ }
+ }
+ }
+ // process any partial progress saved
+ if (curBlock)
+ {
+ res = RemovePartOfBlock(curBlock, firstNode, lastNode);
+ if (NS_FAILED(res)) return res;
+ curBlock = 0; firstNode = 0; lastNode = 0;
+ }
+ return res;
+}
+
+
///////////////////////////////////////////////////////////////////////////
// ApplyBlockStyle: do whatever it takes to make the list of nodes into
// one or more blocks of type blockTag.
@@ -4786,15 +5067,8 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsAReadab
nsCOMPtr curNode, curParent, curBlock, newBlock;
PRInt32 offset;
PRUint32 listCount;
- PRBool bNoParent = PR_FALSE;
-
- // we special case an empty tag name to mean "remove block parents".
- // This is used for the "normal" paragraph style in mail-compose
nsString tString(*aBlockTag);////MJUDGE SCC NEED HELP
- if (tString.IsEmpty() ||
- !Compare(tString,NS_LITERAL_STRING("normal"),nsCaseInsensitiveStringComparator()))
- bNoParent = PR_TRUE;
-
+
arrayOfNodes->Count(&listCount);
PRUint32 i;
@@ -4810,13 +5084,13 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsAReadab
curNodeTag.ToLowerCase();
// is it already the right kind of block?
- if (!bNoParent && curNodeTag == *aBlockTag)
+ if (curNodeTag == *aBlockTag)
{
curBlock = 0; // forget any previous block used for previous inline nodes
continue; // do nothing to this block
}
- // if curNode is a mozdiv, p, header, address, or pre, replace
+ // if curNode is a address, p, header, address, or pre, replace
// it with a new block of correct type.
// xxx floppy moose: pre cant hold everything the others can
if (nsHTMLEditUtils::IsMozDiv(curNode) ||
@@ -4831,17 +5105,7 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsAReadab
(curNodeTag.EqualsWithConversion("address")))
{
curBlock = 0; // forget any previous block used for previous inline nodes
- if (bNoParent)
- {
- // make sure we have a normal br at end of block
- res = AddTerminatingBR(curNode);
- if (NS_FAILED(res)) return res;
- res = mHTMLEditor->RemoveContainer(curNode);
- }
- else
- {
- res = mHTMLEditor->ReplaceContainer(curNode, address_of(newBlock), *aBlockTag);
- }
+ res = mHTMLEditor->ReplaceContainer(curNode, address_of(newBlock), *aBlockTag);
if (NS_FAILED(res)) return res;
}
else if ((curNodeTag.EqualsWithConversion("table")) ||
@@ -4850,9 +5114,10 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsAReadab
(curNodeTag.EqualsWithConversion("td")) ||
(curNodeTag.EqualsWithConversion("ol")) ||
(curNodeTag.EqualsWithConversion("ul")) ||
+ (curNodeTag.EqualsWithConversion("dl")) ||
(curNodeTag.EqualsWithConversion("li")) ||
(curNodeTag.EqualsWithConversion("blockquote")) ||
- (curNodeTag.EqualsWithConversion("div"))) // div's other than mozdivs
+ (curNodeTag.EqualsWithConversion("div")))
{
curBlock = 0; // forget any previous block used for previous inline nodes
// recursion time
@@ -4867,11 +5132,8 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsAReadab
else if (curNodeTag.EqualsWithConversion("br"))
{
curBlock = 0; // forget any previous block used for previous inline nodes
- if (!bNoParent)
- {
- res = mHTMLEditor->DeleteNode(curNode);
- if (NS_FAILED(res)) return res;
- }
+ res = mHTMLEditor->DeleteNode(curNode);
+ if (NS_FAILED(res)) return res;
}
@@ -4882,7 +5144,7 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsAReadab
// arrayOfNodes is contructed, but some additional logic should
// be added here if that should change
- else if (IsInlineNode(curNode) && !bNoParent)
+ else if (IsInlineNode(curNode))
{
// if curNode is a non editable, drop it if we are going to
if (!Compare(tString,NS_LITERAL_STRING("pre"),nsCaseInsensitiveStringComparator())
@@ -4958,43 +5220,6 @@ nsHTMLEditRules::SplitAsNeeded(const nsAReadableString *aTag,
return res;
}
-///////////////////////////////////////////////////////////////////////////
-// AddTerminatingBR: place an ordinary br node at the end of aBlock,
-// if it doens't already have one. If it has a moz-BR,
-// simply convertit to a normal br.
-nsresult
-nsHTMLEditRules::AddTerminatingBR(nsIDOMNode *aBlock)
-{
- if (!aBlock) return NS_ERROR_NULL_POINTER;
- nsCOMPtr last;
- nsresult res = mHTMLEditor->GetLastEditableLeaf(aBlock, address_of(last));
- if (last && nsTextEditUtils::IsBreak(last))
- {
- if (nsTextEditUtils::IsMozBR(last))
- {
- // need to convert a br
- nsCOMPtr elem = do_QueryInterface(last);
- res = mHTMLEditor->RemoveAttribute(elem, NS_ConvertASCIItoUCS2("type"));
- if (NS_FAILED(res)) return res;
- }
- else // we have what we want, we're done
- {
- return res;
- }
- }
- else // need to add a br
- {
- PRUint32 len;
- nsCOMPtr brNode;
- res = mHTMLEditor->GetLengthOfDOMNode(aBlock, len);
- if (NS_FAILED(res)) return res;
- res = mHTMLEditor->CreateBR(aBlock, len, address_of(brNode));
- if (NS_FAILED(res)) return res;
- }
- return res;
-}
-
-
///////////////////////////////////////////////////////////////////////////
// JoinNodesSmart: join two nodes, doing whatever makes sense for their
// children (which often means joining them, too).
@@ -5744,9 +5969,7 @@ nsHTMLEditRules::PopListItem(nsIDOMNode *aListItem, PRBool *aOutOfList)
if (!nsHTMLEditUtils::IsList(curParPar)
&& nsHTMLEditUtils::IsListItem(curNode))
{
- res = AddTerminatingBR(curNode);
- if (NS_FAILED(res)) return res;
- res = mHTMLEditor->RemoveContainer(curNode);
+ res = mHTMLEditor->RemoveBlockContainer(curNode);
if (NS_FAILED(res)) return res;
*aOutOfList = PR_TRUE;
}
@@ -5788,7 +6011,7 @@ nsHTMLEditRules::RemoveListStructure(nsIDOMNode *aList)
aList->GetFirstChild(getter_AddRefs(child));
}
// delete the now-empty list
- res = mHTMLEditor->DeleteNode(aList);
+ res = mHTMLEditor->RemoveBlockContainer(aList);
if (NS_FAILED(res)) return res;
return res;
@@ -6128,12 +6351,3 @@ nsHTMLEditRules::DidDeleteSelection(nsISelection *aSelection)
{
return NS_OK;
}
-
-
-
-
-
-
-
-
-
diff --git a/mozilla/editor/libeditor/html/nsHTMLEditRules.h b/mozilla/editor/libeditor/html/nsHTMLEditRules.h
index 8a499f5c4f3..4a770413e47 100644
--- a/mozilla/editor/libeditor/html/nsHTMLEditRules.h
+++ b/mozilla/editor/libeditor/html/nsHTMLEditRules.h
@@ -122,6 +122,9 @@ protected:
nsresult ReturnInParagraph(nsISelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset, PRBool *aCancel, PRBool *aHandled);
nsresult ReturnInListItem(nsISelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset);
nsresult AfterEditInner(PRInt32 action, nsIEditor::EDirection aDirection);
+ nsresult RemovePartOfBlock(nsIDOMNode *curBlockQuote,
+ nsIDOMNode *firstBQChild,
+ nsIDOMNode *lastBQChild);
nsresult ConvertListType(nsIDOMNode *aList, nsCOMPtr *outList, const nsAReadableString& aListType, const nsAReadableString& aItemType);
nsresult CreateStyleForInsertText(nsISelection *aSelection, nsIDOMDocument *aDoc);
nsresult IsEmptyBlock(nsIDOMNode *aNode,
@@ -155,12 +158,14 @@ protected:
nsresult GetListActionNodes(nsCOMPtr *outArrayOfNodes, PRBool aEntireList, PRBool aDontTouchContent=PR_FALSE);
nsresult GetDefinitionListItemTypes(nsIDOMNode *aNode, PRBool &aDT, PRBool &aDD);
nsresult GetParagraphFormatNodes(nsCOMPtr *outArrayOfNodes, PRBool aDontTouchContent=PR_FALSE);
+ nsresult LookInsideDivBQandList(nsISupportsArray *aNodeArray);
nsresult BustUpInlinesAtRangeEndpoints(nsRangeStore &inRange);
nsresult BustUpInlinesAtBRs(nsIDOMNode *inNode,
nsCOMPtr *outArrayOfNodes);
nsCOMPtr GetHighestInlineParent(nsIDOMNode* aNode);
nsresult MakeTransitionList(nsISupportsArray *inArrayOfNodes,
nsVoidArray *inTransitionArray);
+ nsresult RemoveBlockStyle(nsISupportsArray *arrayOfNodes);
nsresult ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsAReadableString *aBlockTag);
nsresult MakeBlockquote(nsISupportsArray *arrayOfNodes);
nsresult SplitAsNeeded(const nsAReadableString *aTag, nsCOMPtr *inOutParent, PRInt32 *inOutOffset);
diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp
index ec9ac4dfaf9..419f8e4637f 100644
--- a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp
@@ -4095,6 +4095,103 @@ nsHTMLEditor::SetSelectionAtDocumentStart(nsISelection *aSelection)
#pragma mark -
#endif
+///////////////////////////////////////////////////////////////////////////
+// RemoveBlockContainer: remove inNode, reparenting it's children into their
+// the parent of inNode. In addition, INSERT ANY BR's NEEDED
+// TO PRESERVE IDENTITY OF REMOVED BLOCK.
+//
+nsresult
+nsHTMLEditor::RemoveBlockContainer(nsIDOMNode *inNode)
+{
+ if (!inNode)
+ return NS_ERROR_NULL_POINTER;
+ nsresult res;
+ nsCOMPtr sibling, child, unused;
+
+ // Two possibilities: the container cold be empty of editable content.
+ // If that is the case, we need to compare what is before and after inNode
+ // to determine if we need a br.
+ // Or it could not be empty, in which case we have to compare previous
+ // sibling and first child to determine if we need a leading br,
+ // and compare following sibling and last child to determine if we need a
+ // trailing br.
+
+ res = GetFirstEditableChild(inNode, address_of(child));
+ if (NS_FAILED(res)) return res;
+
+ if (child) // the case of inNode not being empty
+ {
+ // we need a br at start unless:
+ // 1) previous sibling of inNode is a block, OR
+ // 2) previous sibling of inNode is a br, OR
+ // 3) first child of inNode is a block OR
+ // 4) either is null
+
+ res = GetPriorHTMLSibling(inNode, address_of(sibling));
+ if (NS_FAILED(res)) return res;
+ if (sibling && !IsBlockNode(sibling) && !nsTextEditUtils::IsBreak(sibling))
+ {
+ res = GetFirstEditableChild(inNode, address_of(child));
+ if (NS_FAILED(res)) return res;
+ if (child && !IsBlockNode(child))
+ {
+ // insert br node
+ res = CreateBR(inNode, 0, address_of(unused));
+ if (NS_FAILED(res)) return res;
+ }
+ }
+
+ // we need a br at end unless:
+ // 1) following sibling of inNode is a block, OR
+ // 2) last child of inNode is a block, OR
+ // 3) last child of inNode is a block OR
+ // 4) either is null
+
+ res = GetNextHTMLSibling(inNode, address_of(sibling));
+ if (NS_FAILED(res)) return res;
+ if (sibling && !IsBlockNode(sibling))
+ {
+ res = GetLastEditableChild(inNode, address_of(child));
+ if (NS_FAILED(res)) return res;
+ if (child && !IsBlockNode(child) && !nsTextEditUtils::IsBreak(child))
+ {
+ // insert br node
+ PRUint32 len;
+ res = GetLengthOfDOMNode(inNode, len);
+ if (NS_FAILED(res)) return res;
+ res = CreateBR(inNode, (PRInt32)len, address_of(unused));
+ if (NS_FAILED(res)) return res;
+ }
+ }
+ }
+ else // the case of inNode being empty
+ {
+ // we need a br at start unless:
+ // 1) previous sibling of inNode is a block, OR
+ // 2) previous sibling of inNode is a br, OR
+ // 3) following sibling of inNode is a block, OR
+ // 4) following sibling of inNode is a br OR
+ // 5) either is null
+ res = GetPriorHTMLSibling(inNode, address_of(sibling));
+ if (NS_FAILED(res)) return res;
+ if (sibling && !IsBlockNode(sibling) && !nsTextEditUtils::IsBreak(sibling))
+ {
+ res = GetNextHTMLSibling(inNode, address_of(sibling));
+ if (NS_FAILED(res)) return res;
+ if (sibling && !IsBlockNode(sibling) && !nsTextEditUtils::IsBreak(sibling))
+ {
+ // insert br node
+ res = CreateBR(inNode, 0, address_of(unused));
+ if (NS_FAILED(res)) return res;
+ }
+ }
+ }
+
+ // now remove container
+ return RemoveContainer(inNode);
+}
+
+
///////////////////////////////////////////////////////////////////////////
// GetPriorHTMLSibling: returns the previous editable sibling, if there is
// one within the parent
@@ -4163,7 +4260,7 @@ nsHTMLEditor::GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr *outNo
{
res = node->GetNextSibling(getter_AddRefs(temp));
if (NS_FAILED(res)) return res;
- if (!temp) return NS_ERROR_FAILURE;
+ if (!temp) return NS_OK; // return null sibling
// if it's editable, we're done
if (IsEditable(temp)) break;
// otherwise try again
diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.h b/mozilla/editor/libeditor/html/nsHTMLEditor.h
index eced4d50cec..f2170f28695 100644
--- a/mozilla/editor/libeditor/html/nsHTMLEditor.h
+++ b/mozilla/editor/libeditor/html/nsHTMLEditor.h
@@ -642,6 +642,7 @@ protected:
PRBool HasMatchingAttributes(nsIDOMNode *aNode1,
nsIDOMNode *aNode2);
+ nsresult RemoveBlockContainer(nsIDOMNode *inNode);
nsresult GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr *outNode);
nsresult GetPriorHTMLSibling(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr *outNode);
nsresult GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr *outNode);