fix for Bug 92331: at long last moving over to using spans instead of pre's for plaintext mailcites. Due to limited testing the pref for this is left *OFF*. we'll flip it on if everything goes well later.

This commit is contained in:
jfrancis%netscape.com 2001-12-12 06:02:15 +00:00
Родитель 9ffa07fd07
Коммит 5e4e01a7c8
6 изменённых файлов: 264 добавлений и 159 удалений

Просмотреть файл

@ -1571,9 +1571,18 @@ nsHTMLEditor::InsertAsPlaintextQuotation(const nsAReadableString & aQuotedText,
{
preElement->SetAttribute(NS_LITERAL_STRING("_moz_quote"),
NS_LITERAL_STRING("true"));
// set style to not have unwanted vertical margins
preElement->SetAttribute(NS_LITERAL_STRING("style"),
NS_LITERAL_STRING("margin: 0 0 0 0px;"));
if (quotesInPre)
{
// set style to not have unwanted vertical margins
preElement->SetAttribute(NS_LITERAL_STRING("style"),
NS_LITERAL_STRING("margin: 0 0 0 0px;"));
}
else
{
// turn off wrapping on spans
preElement->SetAttribute(NS_LITERAL_STRING("style"),
NS_LITERAL_STRING("white-space: pre;"));
}
}
// and set the selection inside it:

Просмотреть файл

@ -1312,7 +1312,8 @@ nsHTMLEditRules::WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBo
if (citeNode)
{
nsCOMPtr<nsIDOMNode> brNode;
res = mHTMLEditor->SplitNodeDeep(citeNode, selNode, selOffset, &newOffset);
res = mHTMLEditor->SplitNodeDeep(citeNode, selNode, selOffset,
&newOffset, PR_TRUE);
if (NS_FAILED(res)) return res;
res = citeNode->GetParentNode(getter_AddRefs(selNode));
if (NS_FAILED(res)) return res;
@ -1322,6 +1323,12 @@ nsHTMLEditRules::WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBo
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;
}
*aHandled = PR_TRUE;
return NS_OK;
}
@ -3087,160 +3094,196 @@ nsHTMLEditRules::WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool *
// initialize out param
*aCancel = PR_FALSE;
*aHandled = PR_TRUE;
nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
nsresult res = NS_OK;
nsCOMPtr<nsIDOMNode> rememberedLeftBQ, rememberedRightBQ;
// convert the selection ranges into "promoted" selection ranges:
// this basically just expands the range to include the immediate
// block parent, and then further expands to include any ancestors
// whose children are all in the range
nsCOMPtr<nsISupportsArray> arrayOfNodes;
res = GetNodesFromSelection(aSelection, kOutdent, address_of(arrayOfNodes));
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<nsIDOMNode> curBlockQuote, firstBQChild, lastBQChild;
PRUint32 listCount;
PRInt32 i;
arrayOfNodes->Count(&listCount);
nsCOMPtr<nsIDOMNode> curParent;
for (i=0; i<(PRInt32)listCount; i++)
// some scoping for selection resetting - we may need to tweak it
{
// here's where we actually figure out what to do
nsCOMPtr<nsISupports> isupports = dont_AddRef(arrayOfNodes->ElementAt(i));
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
PRInt32 offset;
res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
// convert the selection ranges into "promoted" selection ranges:
// this basically just expands the range to include the immediate
// block parent, and then further expands to include any ancestors
// whose children are all in the range
nsCOMPtr<nsISupportsArray> arrayOfNodes;
res = GetNodesFromSelection(aSelection, kOutdent, address_of(arrayOfNodes));
if (NS_FAILED(res)) return res;
// is it a blockquote?
if (nsHTMLEditUtils::IsBlockquote(curNode))
{
// if it is a blockquote, remove it.
// So we need to finish up dealng with any curBlockQuote first.
if (curBlockQuote)
{
res = RemovePartOfBlock(curBlockQuote, firstBQChild, lastBQChild);
if (NS_FAILED(res)) return res;
curBlockQuote = 0; firstBQChild = 0; lastBQChild = 0;
}
res = mHTMLEditor->RemoveBlockContainer(curNode);
if (NS_FAILED(res)) return res;
continue;
}
// is it a list item?
if (nsHTMLEditUtils::IsListItem(curNode))
{
// 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)
{
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<nsIDOMNode> n = curNode;
nsCOMPtr<nsIDOMNode> 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)
// Ok, now go through all the nodes and remove a level of blockquoting,
// or whatever is appropriate. Wohoo!
nsCOMPtr<nsIDOMNode> curBlockQuote, firstBQChild, lastBQChild;
PRUint32 listCount;
PRInt32 i;
arrayOfNodes->Count(&listCount);
nsCOMPtr<nsIDOMNode> curParent;
for (i=0; i<(PRInt32)listCount; i++)
{
// could not find an enclosing blockquote for this node. handle list cases.
if (nsHTMLEditUtils::IsList(curParent)) // move node out of list
// here's where we actually figure out what to do
nsCOMPtr<nsISupports> isupports = dont_AddRef(arrayOfNodes->ElementAt(i));
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
PRInt32 offset;
res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
if (NS_FAILED(res)) return res;
// 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 = RemovePartOfBlock(curBlockQuote, firstBQChild, lastBQChild,
address_of(rememberedLeftBQ), address_of(rememberedRightBQ));
if (NS_FAILED(res)) return res;
curBlockQuote = 0; firstBQChild = 0; lastBQChild = 0;
}
res = mHTMLEditor->RemoveBlockContainer(curNode);
if (NS_FAILED(res)) return res;
continue;
}
// is it a list item?
if (nsHTMLEditUtils::IsListItem(curNode))
{
// 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)
{
res = RemovePartOfBlock(curBlockQuote, firstBQChild, lastBQChild,
address_of(rememberedLeftBQ), address_of(rememberedRightBQ));
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,
address_of(rememberedLeftBQ), address_of(rememberedRightBQ));
if (NS_FAILED(res)) return res;
curBlockQuote = 0; firstBQChild = 0; lastBQChild = 0;
// fall out and handle curNode
}
}
// are we inside a blockquote?
nsCOMPtr<nsIDOMNode> n = curNode;
nsCOMPtr<nsIDOMNode> 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<nsIDOMNode> 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;
}
// handled list item case above
}
else if (nsHTMLEditUtils::IsList(curNode)) // node is a list, but parent is non-list: move list items out
}
if (curBlockQuote)
{
// we have a blockquote we haven't finished handling
res = RemovePartOfBlock(curBlockQuote, firstBQChild, lastBQChild,
address_of(rememberedLeftBQ), address_of(rememberedRightBQ));
if (NS_FAILED(res)) return res;
}
}
// make sure selection didn't stick to last piece of content in old bq
// (only a roblem for collapsed selections)
if (rememberedLeftBQ || rememberedRightBQ)
{
PRBool bCollapsed;
res = aSelection->GetIsCollapsed(&bCollapsed);
if (bCollapsed)
{
// push selection past end of rememberedLeftBQ
nsCOMPtr<nsIDOMNode> sNode;
PRInt32 sOffset;
mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(sNode), &sOffset);
if ((sNode == rememberedLeftBQ) || nsHTMLEditUtils::IsDescendantOf(sNode, rememberedLeftBQ))
{
nsCOMPtr<nsIDOMNode> 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;
// selection is inside rememberedLeftBQ - push it past it.
nsEditor::GetNodeLocation(rememberedLeftBQ, address_of(sNode), &sOffset);
sOffset++;
aSelection->Collapse(sNode, sOffset);
}
// and pull selection before beginning of rememberedRightBQ
mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(sNode), &sOffset);
if ((sNode == rememberedRightBQ) || nsHTMLEditUtils::IsDescendantOf(sNode, rememberedRightBQ))
{
// selection is inside rememberedRightBQ - push it before it.
nsEditor::GetNodeLocation(rememberedRightBQ, address_of(sNode), &sOffset);
aSelection->Collapse(sNode, sOffset);
}
}
}
if (curBlockQuote)
{
// we have a blockquote we haven't finished handling
res = RemovePartOfBlock(curBlockQuote, firstBQChild, lastBQChild);
if (NS_FAILED(res)) return res;
}
return res;
}
@ -3252,7 +3295,9 @@ nsHTMLEditRules::WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool *
nsresult
nsHTMLEditRules::RemovePartOfBlock(nsIDOMNode *aBlock,
nsIDOMNode *aStartChild,
nsIDOMNode *aEndChild)
nsIDOMNode *aEndChild,
nsCOMPtr<nsIDOMNode> *aLeftNode,
nsCOMPtr<nsIDOMNode> *aRightNode)
{
if (!aBlock || !aStartChild || !aEndChild)
return NS_ERROR_NULL_POINTER;
@ -3271,6 +3316,10 @@ nsHTMLEditRules::RemovePartOfBlock(nsIDOMNode *aBlock,
if (NS_FAILED(res)) return res;
if (rightNode) aBlock = rightNode;
// remember left portion of block if caller requested
if (aLeftNode)
*aLeftNode = leftNode;
// get split point location
res = nsEditor::GetNodeLocation(aEndChild, address_of(endParent), &endOffset);
if (NS_FAILED(res)) return res;
@ -3282,8 +3331,13 @@ nsHTMLEditRules::RemovePartOfBlock(nsIDOMNode *aBlock,
if (NS_FAILED(res)) return res;
if (leftNode) aBlock = leftNode;
// remember right portion of block if caller requested
if (aRightNode)
*aRightNode = rightNode;
// get rid of part of blockquote we are outdenting
res = mHTMLEditor->RemoveBlockContainer(aBlock);
return res;
}
@ -5972,7 +6026,7 @@ nsHTMLEditRules::GetTopEnclosingMailCite(nsIDOMNode *aNode,
while (node)
{
if ( (aPlainText && nsHTMLEditUtils::IsPre(node)) ||
(!aPlainText && nsHTMLEditUtils::IsMailCite(node)) )
nsHTMLEditUtils::IsMailCite(node) )
*aOutCiteNode = node;
if (nsTextEditUtils::IsBody(node)) break;

Просмотреть файл

@ -152,9 +152,11 @@ 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 RemovePartOfBlock(nsIDOMNode *aBlock,
nsIDOMNode *aStartChild,
nsIDOMNode *aEndChild,
nsCOMPtr<nsIDOMNode> *aLeftNode = 0,
nsCOMPtr<nsIDOMNode> *aRightNode = 0);
nsresult ConvertListType(nsIDOMNode *aList, nsCOMPtr<nsIDOMNode> *outList, const nsAReadableString& aListType, const nsAReadableString& aItemType);
nsresult CreateStyleForInsertText(nsISelection *aSelection, nsIDOMDocument *aDoc);
nsresult IsEmptyBlock(nsIDOMNode *aNode,

Просмотреть файл

@ -376,19 +376,30 @@ PRBool
nsHTMLEditUtils::IsMailCite(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null parent passed to nsHTMLEditUtils::IsMailCite");
if (IsBlockquote(node))
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(node);
if (!elem) return PR_FALSE;
nsAutoString attrName (NS_LITERAL_STRING("type"));
// don't ask me why, but our html mailcites are id'd by "type=cite"...
nsAutoString attrVal;
nsresult res = elem->GetAttribute(attrName, attrVal);
attrVal.ToLowerCase();
if (NS_SUCCEEDED(res))
{
nsCOMPtr<nsIDOMElement> bqElem = do_QueryInterface(node);
nsAutoString typeAttrName(NS_LITERAL_STRING("type"));
nsAutoString typeAttrVal;
nsresult res = bqElem->GetAttribute(typeAttrName, typeAttrVal);
typeAttrVal.ToLowerCase();
if (NS_SUCCEEDED(res))
{
if (typeAttrVal.EqualsWithConversion("cite", PR_TRUE, 4))
return PR_TRUE;
}
if (attrVal.Equals(NS_LITERAL_STRING("cite")))
return PR_TRUE;
}
// ... but our plaintext mailcites by "_moz_quote=true". go figure.
attrName.Assign(NS_LITERAL_STRING("_moz_quote"));
res = elem->GetAttribute(attrName, attrVal);
if (NS_SUCCEEDED(res))
{
attrVal.ToLowerCase();
if (attrVal.Equals(NS_LITERAL_STRING("true")))
return PR_TRUE;
}
return PR_FALSE;
}
@ -413,6 +424,26 @@ nsHTMLEditUtils::IsMap(nsIDOMNode *node)
}
///////////////////////////////////////////////////////////////////////////
// IsFormWidget: true if node is a form widget of some kind
//
PRBool
nsHTMLEditUtils::IsFormWidget(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null node passed to nsHTMLEditUtils::IsFormWidget");
nsAutoString tag;
nsEditor::GetTagString(node,tag);
tag.ToLowerCase();
if (tag.Equals(NS_LITERAL_STRING("textarea")) ||
tag.Equals(NS_LITERAL_STRING("select")) ||
tag.Equals(NS_LITERAL_STRING("button")) ||
tag.Equals(NS_LITERAL_STRING("input")) )
{
return PR_TRUE;
}
return PR_FALSE;
}
PRBool
nsHTMLEditUtils::IsDescendantOf(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 *aOffset)
{

Просмотреть файл

@ -78,6 +78,7 @@ public:
static PRBool IsMailCite(nsIDOMNode *aNode);
static PRBool IsTextarea(nsIDOMNode *aNode);
static PRBool IsMap(nsIDOMNode *aNode);
static PRBool IsFormWidget(nsIDOMNode *aNode);
static PRBool IsDescendantOf(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 *aOffset = 0);
static PRBool IsLeafNode(nsIDOMNode *aNode);

Просмотреть файл

@ -4706,8 +4706,9 @@ nsHTMLEditor::IsEmptyNode( nsIDOMNode *aNode,
// Also, if it's an anchor then dont treat it as empty - even though
// anchors are containers, named anchors are "empty" but we don't
// want to treat them as such. Also, don't call ListItems or table
// cells empty if caller desires.
// cells empty if caller desires. Form Widgets not empty.
if (!IsContainer(aNode) || nsHTMLEditUtils::IsNamedAnchor(aNode) ||
nsHTMLEditUtils::IsFormWidget(aNode) ||
(aListOrCellNotEmpty && nsHTMLEditUtils::IsListItem(aNode)) ||
(aListOrCellNotEmpty && nsHTMLEditUtils::IsTableCell(aNode)) )
{
@ -4804,6 +4805,13 @@ nsHTMLEditor::IsEmptyNode( nsIDOMNode *aNode,
break;
}
}
// is it a form widget?
else if (nsHTMLEditUtils::IsFormWidget(aNode))
{
*outIsEmptyNode = PR_FALSE;
break;
}
PRBool isEmptyNode;
res = IsEmptyNode(node, &isEmptyNode, aSingleBRDoesntCount, aListOrCellNotEmpty);
if (NS_FAILED(res)) return res;