* ported the html editor work for the "caret doesn't move when i hit return" bug (16715) back to the plaintext editor.

This commit is contained in:
jfrancis%netscape.com 1999-11-29 08:28:46 +00:00
Родитель 8abfb4a29e
Коммит d4edc684b8
10 изменённых файлов: 1308 добавлений и 1112 удалений

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

@ -88,6 +88,26 @@ nsHTMLEditRules::Init(nsHTMLEditor *aEditor, PRUint32 aFlags)
nsresult res = nsTextEditRules::Init(aEditor, aFlags);
if (NS_FAILED(res)) return res;
// pass over document and add any needed mozBRs
// first turn off undo
mEditor->EnableUndo(PR_FALSE);
// set up mDocChangeRange to be whole doc
nsCOMPtr<nsIDOMElement> bodyElem;
nsCOMPtr<nsIDOMNode> bodyNode;
mEditor->GetBodyElement(getter_AddRefs(bodyElem));
bodyNode = do_QueryInterface(bodyElem);
if (bodyNode)
{
res = nsComponentManager::CreateInstance(kRangeCID, nsnull, nsIDOMRange::GetIID(),
getter_AddRefs(mDocChangeRange));
if (NS_FAILED(res)) return res;
if (!mDocChangeRange) return NS_ERROR_NULL_POINTER;
mDocChangeRange->SelectNode(bodyNode);
AdjustSpecialBreaks();
}
// turn on undo
mEditor->EnableUndo(PR_TRUE);
// make a listener
res = NS_NewEditListener(getter_AddRefs(mListener), mEditor, this);
if (NS_FAILED(res)) return res;
@ -198,8 +218,11 @@ nsHTMLEditRules::DidDoAction(nsIDOMSelection *aSelection,
}
// do default:
res = nsTextEditRules::DidDoAction(aSelection, aInfo, aResult);
if (NS_FAILED(res)) return res;
if (aInfo->action != kInsertBreak) // nsTextEditRules::DidInsertBreak() not usable by html rules
{
res = nsTextEditRules::DidDoAction(aSelection, aInfo, aResult);
if (NS_FAILED(res)) return res;
}
// adjust selection
res = AdjustSelection(aSelection,info->collapsedAction);
return res;
@ -211,52 +234,6 @@ nsHTMLEditRules::DidDoAction(nsIDOMSelection *aSelection,
********************************************************/
nsresult
nsHTMLEditRules::WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel)
{
if (!aSelection || !aCancel)
return NS_ERROR_NULL_POINTER;
nsresult res = nsTextEditRules::WillInsert(aSelection, aCancel);
if (NS_FAILED(res)) return res;
// this next only works for collapsed selections right now,
// because selection is a pain to work with when not collapsed.
// (no good way to extend start or end of selection)
PRBool bCollapsed;
res = aSelection->GetIsCollapsed(&bCollapsed);
if (NS_FAILED(res)) return res;
if (!bCollapsed) return NS_OK;
// if we are after a mozBR in the same block, then move selection
// to be before it
nsCOMPtr<nsIDOMNode> selNode, priorNode;
PRInt32 selOffset;
// get the (collapsed) selection location
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
// get prior node
nsCOMPtr<nsIDOMNode> block1, block2;
if (mEditor->IsBlockNode(selNode)) block1 = selNode;
else block1 = mEditor->GetBlockNodeParent(selNode);
if (mEditor->IsBlockNode(priorNode)) block2 = priorNode;
else block2 = mEditor->GetBlockNodeParent(priorNode);
if (block1 != block2) return NS_OK;
if (!IsMozBR(priorNode)) 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, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
res = aSelection->Collapse(selNode,selOffset);
if (NS_FAILED(res)) return res;
return NS_OK;
}
nsresult
nsHTMLEditRules::WillInsertText(PRInt32 aAction,
nsIDOMSelection *aSelection,
@ -266,7 +243,8 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
nsString *outString,
TypeInState typeInState,
PRInt32 aMaxLength)
{ if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
{
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
// initialize out param
*aCancel = PR_FALSE;
@ -332,19 +310,6 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
// find a nearby text node if possible
nsCOMPtr<nsIDOMNode> priorNode, nextNode;
res = GetPriorHTMLNode(selNode, selOffset, &priorNode);
// are we after a mozBR?
if (NS_SUCCEEDED(res) && priorNode && IsMozBR(priorNode)
&& (blockParent == mEditor->GetBlockNodeParent(priorNode)))
{
// uhh, lets be before it instead of after it. Now
// walk away reeeal slow...
res = nsEditor::GetNodeLocation(priorNode, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
res = aSelection->Collapse(selNode, selOffset);
if (NS_FAILED(res)) return res;
// we know we are still not in a text node, so fall through to rest of this case
res = GetPriorHTMLNode(selNode, selOffset, &priorNode);
}
if (NS_SUCCEEDED(res) && priorNode && mEditor->IsTextNode(priorNode)
&& (blockParent == mEditor->GetBlockNodeParent(priorNode)))
{
@ -464,17 +429,10 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
*aCancel = PR_FALSE;
*aHandled = PR_FALSE;
nsresult res;
res = WillInsert(aSelection, aCancel);
if (NS_FAILED(res)) return res;
// initialize out param
// we want to ignore result of WillInsert()
*aCancel = PR_FALSE;
// if the selection isn't collapsed, delete it.
PRBool bCollapsed;
res = aSelection->GetIsCollapsed(&bCollapsed);
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
if (NS_FAILED(res)) return res;
if (!bCollapsed)
{
@ -482,6 +440,14 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
if (NS_FAILED(res)) return res;
}
res = WillInsert(aSelection, aCancel);
if (NS_FAILED(res)) return res;
// initialize out param
// we want to ignore result of WillInsert()
*aCancel = PR_FALSE;
// split any mailcites in the way
if (mFlags & nsIHTMLEditor::eEditorMailMask)
{
@ -592,23 +558,6 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
// its something else (body, div, td, ...): insert a normal br
else
{
nsCOMPtr<nsIDOMNode> nearNode;
res = GetPriorHTMLNode(node, offset, &nearNode);
if (NS_FAILED(res)) return res;
if (nearNode && IsBreak(nearNode) && IsMozBR(nearNode))
{
// is nearNode also a descendant of same block?
nsCOMPtr<nsIDOMNode> nearBlock = mEditor->GetBlockNodeParent(nearNode);
if (blockParent == nearBlock)
{
// need to insert special BEFORE the moz BR. Why? Because if we don't
// the selectin adjusting code will add an extra BR. doh.
res = nsEditor::GetNodeLocation(nearNode, &node, &offset);
if (NS_FAILED(res)) return res;
res = aSelection->Collapse(node, offset);
if (NS_FAILED(res)) return res;
}
}
nsCOMPtr<nsIDOMNode> brNode;
res = mEditor->CreateBR(node, offset, &brNode);
if (NS_FAILED(res)) return res;
@ -1830,42 +1779,6 @@ nsHTMLEditRules::IsUnorderedList(nsIDOMNode *node)
}
///////////////////////////////////////////////////////////////////////////
// IsBreak: true if node an html break node
//
PRBool
nsHTMLEditRules::IsBreak(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsBreak");
nsAutoString tag;
nsEditor::GetTagString(node,tag);
tag.ToLowerCase();
if (tag == "br")
{
return PR_TRUE;
}
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsBody: true if node an html body node
//
PRBool
nsHTMLEditRules::IsBody(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsBody");
nsAutoString tag;
nsEditor::GetTagString(node,tag);
tag.ToLowerCase();
if (tag == "body")
{
return PR_TRUE;
}
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsBlockquote: true if node an html blockquote node
//
@ -1942,39 +1855,6 @@ nsHTMLEditRules::IsMozDiv(nsIDOMNode *node)
}
///////////////////////////////////////////////////////////////////////////
// IsMozBR: true if node an html br node with type = _moz
//
PRBool
nsHTMLEditRules::IsMozBR(nsIDOMNode *node)
{
if (IsBreak(node) && HasMozAttr(node)) return PR_TRUE;
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// HasMozAttr: true if node has type attribute = _moz
// (used to indicate the div's and br's we use in
// mail compose rules)
//
PRBool
nsHTMLEditRules::HasMozAttr(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::HasMozAttr");
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(node);
if (elem)
{
nsAutoString typeAttrName("type");
nsAutoString typeAttrVal;
nsresult res = elem->GetAttribute(typeAttrName, typeAttrVal);
typeAttrVal.ToLowerCase();
if (NS_SUCCEEDED(res) && (typeAttrVal == "_moz"))
return PR_TRUE;
}
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsMailCite: true if node an html blockquote with type=cite
@ -2000,26 +1880,6 @@ nsHTMLEditRules::IsMailCite(nsIDOMNode *node)
}
///////////////////////////////////////////////////////////////////////////
// InBody: true if node is a descendant of the body
//
PRBool
nsHTMLEditRules::InBody(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::InBody");
nsCOMPtr<nsIDOMNode> tmp;
nsCOMPtr<nsIDOMNode> p = do_QueryInterface(node);
while (p && !IsBody(p))
{
if ( NS_FAILED(p->GetParentNode(getter_AddRefs(tmp))) || !tmp) // no parent, ran off top of tree
return PR_FALSE;
p = tmp;
}
if (p) return PR_TRUE;
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsEmptyBlock: figure out if aNode is (or is inside) an empty block.
// A block can have children and still be considered empty,
@ -2181,143 +2041,6 @@ nsHTMLEditRules::CreateMozDiv(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<n
}
#endif
///////////////////////////////////////////////////////////////////////////
// GetPriorHTMLSibling: returns the previous editable sibling, if there is
// one within the parent
//
nsresult
nsHTMLEditRules::GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = NS_OK;
*outNode = nsnull;
nsCOMPtr<nsIDOMNode> temp, node = do_QueryInterface(inNode);
while (1)
{
res = node->GetPreviousSibling(getter_AddRefs(temp));
if (NS_FAILED(res)) return res;
if (!temp) return NS_ERROR_FAILURE;
// if it's editable, we're done
if (mEditor->IsEditable(temp)) break;
// otherwise try again
node = temp;
}
*outNode = temp;
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetNextHTMLSibling: returns the next editable sibling, if there is
// one within the parent
//
nsresult
nsHTMLEditRules::GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = NS_OK;
*outNode = nsnull;
nsCOMPtr<nsIDOMNode> temp, node = do_QueryInterface(inNode);
while (1)
{
res = node->GetNextSibling(getter_AddRefs(temp));
if (NS_FAILED(res)) return res;
if (!temp) return NS_ERROR_FAILURE;
// if it's editable, we're done
if (mEditor->IsEditable(temp)) break;
// otherwise try again
node = temp;
}
*outNode = temp;
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetPriorHTMLNode: returns the previous editable leaf node, if there is
// one within the <body>
//
nsresult
nsHTMLEditRules::GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->GetPriorNode(inNode, PR_TRUE, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// if it's not in the body, then zero it out
if (*outNode && !InBody(*outNode))
{
*outNode = nsnull;
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetPriorHTMLNode: same as above but takes {parent,offset} instead of node
//
nsresult
nsHTMLEditRules::GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->GetPriorNode(inParent, inOffset, PR_TRUE, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// if it's not in the body, then zero it out
if (*outNode && !InBody(*outNode))
{
*outNode = nsnull;
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetNextHTMLNode: returns the previous editable leaf node, if there is
// one within the <body>
//
nsresult
nsHTMLEditRules::GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->GetNextNode(inNode, PR_TRUE, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// if it's not in the body, then zero it out
if (*outNode && !InBody(*outNode))
{
*outNode = nsnull;
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetNHTMLextNode: same as above but takes {parent,offset} instead of node
//
nsresult
nsHTMLEditRules::GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->GetNextNode(inParent, inOffset, PR_TRUE, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// if it's not in the body, then zero it out
if (*outNode && !InBody(*outNode))
{
*outNode = nsnull;
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetTabAsNBSPs: stuff the right number of nbsp's into outString
//
@ -2352,17 +2075,27 @@ nsHTMLEditRules::IsFirstNode(nsIDOMNode *aNode)
{
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset, j=0;
nsEditor::GetNodeLocation(aNode, &parent, &offset);
nsresult res = nsEditor::GetNodeLocation(aNode, &parent, &offset);
if (NS_FAILED(res))
{
NS_NOTREACHED("failure in nsHTMLEditRules::IsFirstNode");
return PR_FALSE;
}
if (!offset) // easy case, we are first dom child
return PR_TRUE;
if (!parent)
return PR_TRUE;
// ok, so there are earlier children. But are they editable???
nsCOMPtr<nsIDOMNodeList>childList;
nsCOMPtr<nsIDOMNode> child;
if (!parent) return PR_TRUE;
parent->GetChildNodes(getter_AddRefs(childList));
res = parent->GetChildNodes(getter_AddRefs(childList));
if (NS_FAILED(res) || !childList)
{
NS_NOTREACHED("failure in nsHTMLEditRules::IsFirstNode");
return PR_TRUE;
}
while (j < offset)
{
childList->Item(j, getter_AddRefs(child));
@ -2383,16 +2116,28 @@ nsHTMLEditRules::IsLastNode(nsIDOMNode *aNode)
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset, j;
PRUint32 numChildren;
nsEditor::GetNodeLocation(aNode, &parent, &offset);
nsresult res = nsEditor::GetNodeLocation(aNode, &parent, &offset);
if (NS_FAILED(res))
{
NS_NOTREACHED("failure in nsHTMLEditRules::IsLastNode");
return PR_FALSE;
}
nsEditor::GetLengthOfDOMNode(parent, numChildren);
if (offset+1 == (PRInt32)numChildren) // easy case, we are last dom child
return PR_TRUE;
if (!parent)
return PR_TRUE;
// ok, so there are later children. But are they editable???
j = offset+1;
nsCOMPtr<nsIDOMNodeList>childList;
nsCOMPtr<nsIDOMNode> child;
parent->GetChildNodes(getter_AddRefs(childList));
res = parent->GetChildNodes(getter_AddRefs(childList));
if (NS_FAILED(res) || !childList)
{
NS_NOTREACHED("failure in nsHTMLEditRules::IsLastNode");
return PR_TRUE;
}
while (j < (PRInt32)numChildren)
{
childList->Item(j, getter_AddRefs(child));
@ -2434,7 +2179,7 @@ nsHTMLEditRules::AtEndOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aB
{
PRUint32 strLength;
nodeAsText->GetLength(&strLength);
if (strLength > aOffset) return PR_FALSE; // there are chars in after us
if ((PRInt32)strLength > aOffset) return PR_FALSE; // there are chars in after us
}
nsCOMPtr<nsIDOMNode> nextNode;
nsresult res = GetNextHTMLNode(aNode, aOffset, &nextNode);
@ -2549,7 +2294,7 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt
// finding the real start for this point. look up the tree for as long as we are the
// first node in the container, and as long as we haven't hit the body node.
nsEditor::GetNodeLocation(node, &parent, &offset);
res = nsEditor::GetNodeLocation(node, &parent, &offset);
if (NS_FAILED(res)) return res;
while ((IsFirstNode(node)) && (!IsBody(parent)))
{
@ -2567,7 +2312,8 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt
// some special casing for text nodes
if (nsEditor::IsTextNode(aNode))
{
nsEditor::GetNodeLocation(aNode, &parent, &offset);
res = nsEditor::GetNodeLocation(aNode, &parent, &offset);
if (NS_FAILED(res)) return res;
}
else
{
@ -2608,7 +2354,7 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt
// finding the real end for this point. look up the tree for as long as we are the
// last node in the container, and as long as we haven't hit the body node.
nsEditor::GetNodeLocation(node, &parent, &offset);
res = nsEditor::GetNodeLocation(node, &parent, &offset);
if (NS_FAILED(res)) return res;
while ((IsLastNode(node)) && (!IsBody(parent)))
{
@ -2782,6 +2528,7 @@ nsHTMLEditRules::GetChildNodesForOperation(nsIDOMNode *inNode,
nsCOMPtr<nsIDOMNodeList> childNodes;
res = inNode->GetChildNodes(getter_AddRefs(childNodes));
if (NS_FAILED(res)) return res;
if (!childNodes) return NS_ERROR_NULL_POINTER;
PRUint32 childCount;
res = childNodes->GetLength(&childCount);
if (NS_FAILED(res)) return res;
@ -3070,27 +2817,6 @@ nsHTMLEditRules::InsertSpace(nsIDOMSelection *aSelection,
}
///////////////////////////////////////////////////////////////////////////
// CreateMozBR: put a BR node with moz attribute at {aNode, aOffset}
//
nsresult
nsHTMLEditRules::CreateMozBR(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outBRNode)
{
if (!inParent || !outBRNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->CreateBR(inParent, inOffset, outBRNode);
if (NS_FAILED(res)) return res;
// give it special moz attr
nsCOMPtr<nsIDOMElement> brElem = do_QueryInterface(*outBRNode);
if (brElem)
{
res = mEditor->SetAttribute(brElem, "type", "_moz");
if (NS_FAILED(res)) return res;
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// ReturnInHeader: do the right thing for returns pressed in headers
//
@ -3186,7 +2912,7 @@ nsHTMLEditRules::ReturnInParagraph(nsIDOMSelection *aSelection,
return res;
}
// at end of text node?
if (aOffset == strLength)
if (aOffset == (PRInt32)strLength)
{
// is there a BR after to it?
res = GetNextHTMLSibling(aNode, &sibling);
@ -3300,7 +3026,7 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,
{
// time to insert a break
nsCOMPtr<nsIDOMNode> brNode;
nsresult res = CreateMozBR(selNode, selOffset, &brNode);
res = CreateMozBR(selNode, selOffset, &brNode);
if (NS_FAILED(res)) return res;
res = nsEditor::GetNodeLocation(brNode, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
@ -3591,104 +3317,6 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString
}
nsresult
nsHTMLEditRules::IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst)
{
// check parms
if (!aOutIsFirst || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutIsFirst = PR_FALSE;
// find first editable child and compare it to aNode
nsCOMPtr<nsIDOMNode> parent, firstChild;
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
if (!parent) return NS_ERROR_FAILURE;
res = GetFirstEditableChild(parent, &firstChild);
if (NS_FAILED(res)) return res;
*aOutIsFirst = (firstChild.get() == aNode);
return res;
}
nsresult
nsHTMLEditRules::IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast)
{
// check parms
if (!aOutIsLast || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutIsLast = PR_FALSE;
// find last editable child and compare it to aNode
nsCOMPtr<nsIDOMNode> parent, lastChild;
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
if (!parent) return NS_ERROR_FAILURE;
res = GetLastEditableChild(parent, &lastChild);
if (NS_FAILED(res)) return res;
*aOutIsLast = (lastChild.get() == aNode);
return res;
}
nsresult
nsHTMLEditRules::GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild)
{
// check parms
if (!aOutFirstChild || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutFirstChild = nsnull;
// find first editable child
nsCOMPtr<nsIDOMNode> child;
nsresult res = aNode->GetFirstChild(getter_AddRefs(child));
if (NS_FAILED(res)) return res;
while (child && !mEditor->IsEditable(child))
{
nsCOMPtr<nsIDOMNode> tmp;
res = child->GetNextSibling(getter_AddRefs(tmp));
if (NS_FAILED(res)) return res;
if (!tmp) return NS_ERROR_FAILURE;
child = tmp;
}
*aOutFirstChild = child;
return res;
}
nsresult
nsHTMLEditRules::GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild)
{
// check parms
if (!aOutLastChild || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutLastChild = nsnull;
// find last editable child
nsCOMPtr<nsIDOMNode> child;
nsresult res = aNode->GetLastChild(getter_AddRefs(child));
if (NS_FAILED(res)) return res;
while (child && !mEditor->IsEditable(child))
{
nsCOMPtr<nsIDOMNode> tmp;
res = child->GetPreviousSibling(getter_AddRefs(tmp));
if (NS_FAILED(res)) return res;
if (!tmp) return NS_ERROR_FAILURE;
child = tmp;
}
*aOutLastChild = child;
return res;
}
///////////////////////////////////////////////////////////////////////////
@ -3846,7 +3474,7 @@ nsHTMLEditRules::AdjustSpecialBreaks()
// put moz-br's into these empty li's and td's
res = arrayOfNodes->Count(&nodeCount);
if (NS_FAILED(res)) return res;
for (j = 0; j < (PRInt32)nodeCount; j++)
for (j = 0; j < nodeCount; j++)
{
isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
nsCOMPtr<nsIDOMNode> brNode, theNode( do_QueryInterface(isupports ) );
@ -3929,7 +3557,7 @@ nsHTMLEditRules::AdjustWhitespace()
// now adjust whitespace on node we found
res = arrayOfNodes->Count(&nodeCount);
if (NS_FAILED(res)) return res;
for (j = 0; j < (PRInt32)nodeCount; j++)
for (j = 0; j < nodeCount; j++)
{
isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
nsCOMPtr<nsIDOMCharacterData> textNode( do_QueryInterface(isupports ) );
@ -3968,7 +3596,7 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::ESelect
// do we need to insert a special mozBR? We do if we are:
// 1) in a collapsed selection AND
// 2) after a normal (non-moz) br AND
// 3) that br in the last editable node in it's block AND
// 3) that br is the last editable node in it's block AND
// 4) that block is same block where selection is
nsCOMPtr<nsIDOMNode> nearNode;
res = GetPriorHTMLNode(selNode, selOffset, &nearNode);
@ -4103,7 +3731,7 @@ nsHTMLEditRules::RemoveEmptyNodes()
// now delete the empty nodes
res = arrayOfNodes->Count(&nodeCount);
if (NS_FAILED(res)) return res;
for (j = 0; j < (PRInt32)nodeCount; j++)
for (j = 0; j < nodeCount; j++)
{
isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
nsCOMPtr<nsIDOMNode> delNode( do_QueryInterface(isupports ) );

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

@ -55,7 +55,6 @@ protected:
// nsHTMLEditRules implementation methods
nsresult WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel);
nsresult WillInsertText( PRInt32 aAction,
nsIDOMSelection *aSelection,
PRBool *aCancel,
@ -92,18 +91,13 @@ protected:
static PRBool IsList(nsIDOMNode *aNode);
static PRBool IsUnorderedList(nsIDOMNode *aNode);
static PRBool IsOrderedList(nsIDOMNode *aNode);
static PRBool IsBreak(nsIDOMNode *aNode);
static PRBool IsBody(nsIDOMNode *aNode);
static PRBool IsBlockquote(nsIDOMNode *aNode);
static PRBool IsAnchor(nsIDOMNode *aNode);
static PRBool IsDiv(nsIDOMNode *aNode);
static PRBool IsNormalDiv(nsIDOMNode *aNode);
static PRBool IsMozDiv(nsIDOMNode *aNode);
static PRBool IsMozBR(nsIDOMNode *aNode);
static PRBool IsMailCite(nsIDOMNode *aNode);
static PRBool HasMozAttr(nsIDOMNode *aNode);
static PRBool InBody(nsIDOMNode *aNode);
nsresult IsEmptyBlock(nsIDOMNode *aNode,
PRBool *outIsEmptyBlock,
@ -118,15 +112,7 @@ protected:
PRBool IsLastNode(nsIDOMNode *aNode);
PRBool AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock);
PRBool AtEndOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock);
nsresult CreateMozBR(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outBRNode);
nsresult GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt32 aOffset,
PRInt32 actionID, nsCOMPtr<nsIDOMNode> *outNode, PRInt32 *outOffset);
nsresult GetPromotedRanges(nsIDOMSelection *inSelection,
@ -148,11 +134,6 @@ protected:
nsresult RemoveContainer(nsIDOMNode *inNode);
nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, const nsString &aNodeType);
nsresult IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst);
nsresult IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast);
nsresult GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild);
nsresult GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild);
nsresult JoinNodesSmart( nsIDOMNode *aNodeLeft,
nsIDOMNode *aNodeRight,
nsCOMPtr<nsIDOMNode> *aOutMergeParent,

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

@ -390,12 +390,6 @@ NS_IMETHODIMP nsHTMLEditor::Init(nsIDOMDocument *aDoc,
}
}
// Init the rules system
// XXX: ERROR CHECKING should InitRules return an error, and then we could check it here?
InitRules();
EnableUndo(PR_TRUE);
// Set up a DTD XXX XXX
// HACK: This should have happened in a document specific way
// in nsEditor::Init(), but we dont' have a way to do that yet
@ -403,6 +397,12 @@ NS_IMETHODIMP nsHTMLEditor::Init(nsIDOMDocument *aDoc,
nsIDTD::GetIID(), getter_AddRefs(mDTD));
if (!mDTD) result = NS_ERROR_FAILURE;
// Init the rules system
// XXX: ERROR CHECKING should InitRules return an error, and then we could check it here?
InitRules();
EnableUndo(PR_TRUE);
return result;
}
@ -1349,97 +1349,99 @@ NS_IMETHODIMP nsHTMLEditor::InsertHTML(const nsString& aInputString)
nsCOMPtr<nsIDOMSelection>selection;
// Call the rules code in case there's anything we need to do first
// (e.g. delete the bogus node):
// Call the rules code in case there's anything we need to do first
// (e.g. delete the bogus node):
if (!mRules) return NS_ERROR_NOT_INITIALIZED;
res = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
nsTextRulesInfo ruleInfo(nsHTMLEditRules::kInsertElement);
PRBool cancel, handled;
res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMNode> parentNode;
PRInt32 offsetOfNewNode;
res = DeleteSelectionAndPrepareToCreateNode(parentNode, offsetOfNewNode);
if (NS_FAILED(res)) return res;
res = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
if (!selection) return NS_ERROR_NULL_POINTER;
// give rules a chance to handle or cancel
nsTextRulesInfo ruleInfo(nsHTMLEditRules::kInsertElement);
PRBool cancel, handled;
res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
if (NS_FAILED(res)) return res;
if (cancel) return NS_OK; // rules canceled the operation
if (!handled)
{
// Get the first range in the selection, for context:
nsCOMPtr<nsIDOMRange> range;
res = selection->GetRangeAt(0, getter_AddRefs(range));
if (NS_FAILED(res))
return res;
nsCOMPtr<nsIDOMNSRange> nsrange (do_QueryInterface(range));
if (!nsrange)
return NS_ERROR_NO_INTERFACE;
nsCOMPtr<nsIDOMDocumentFragment> docfrag;
res = nsrange->CreateContextualFragment(aInputString,
getter_AddRefs(docfrag));
if (NS_FAILED(res))
{
#ifdef DEBUG
printf("Couldn't create contextual fragment: error was %d\n", res);
#endif
return res;
}
#if defined(DEBUG_akkana_verbose)
printf("============ Fragment dump :===========\n");
nsCOMPtr<nsIContent> fragc (do_QueryInterface(docfrag));
if (!fragc)
printf("Couldn't get fragment is nsIContent\n");
else
fragc->List(stdout);
#endif
// Insert the contents of the document fragment:
nsCOMPtr<nsIDOMNode> fragmentAsNode (do_QueryInterface(docfrag));
// Loop over the contents of the fragment:
nsCOMPtr<nsIDOMNode> child;
res = fragmentAsNode->GetFirstChild(getter_AddRefs(child));
if (NS_FAILED(res))
{
printf("GetFirstChild failed!\n");
return res;
}
while (child)
{
#if defined(DEBUG_akkana_verbose)
printf("About to try to insert this node:\n");
nsCOMPtr<nsIContent> nodec (do_QueryInterface(child));
if (nodec) nodec->List(stdout);
printf("-----\n");
#endif
// Get the next sibling before inserting the node;
// when we insert the node, it moves into the main doc tree
// so we'll no longer be able to get the siblings in the doc frag.
nsCOMPtr<nsIDOMNode> nextSib;
child->GetNextSibling(getter_AddRefs(nextSib));
// Ignore the return value, we'll check child when we loop around again.
// Now we can insert the node.
res = InsertNode(child, parentNode, offsetOfNewNode++);
nsCOMPtr<nsIDOMRange> range;
res = selection->GetRangeAt(0, getter_AddRefs(range));
if (NS_FAILED(res))
break;
child = nextSib;
return res;
nsCOMPtr<nsIDOMNSRange> nsrange (do_QueryInterface(range));
if (!nsrange)
return NS_ERROR_NO_INTERFACE;
nsCOMPtr<nsIDOMDocumentFragment> docfrag;
res = nsrange->CreateContextualFragment(aInputString,
getter_AddRefs(docfrag));
if (NS_FAILED(res))
{
#ifdef DEBUG
printf("Couldn't create contextual fragment: error was %d\n", res);
#endif
return res;
}
#if defined(DEBUG_akkana_verbose)
printf("============ Fragment dump :===========\n");
nsCOMPtr<nsIContent> fragc (do_QueryInterface(docfrag));
if (!fragc)
printf("Couldn't get fragment is nsIContent\n");
else
fragc->List(stdout);
#endif
// Insert the contents of the document fragment:
nsCOMPtr<nsIDOMNode> fragmentAsNode (do_QueryInterface(docfrag));
// Loop over the contents of the fragment:
nsCOMPtr<nsIDOMNode> child;
res = fragmentAsNode->GetFirstChild(getter_AddRefs(child));
if (NS_FAILED(res))
{
printf("GetFirstChild failed!\n");
return res;
}
while (child)
{
#if defined(DEBUG_akkana_verbose)
printf("About to try to insert this node:\n");
nsCOMPtr<nsIContent> nodec (do_QueryInterface(child));
if (nodec) nodec->List(stdout);
printf("-----\n");
#endif
// Get the next sibling before inserting the node;
// when we insert the node, it moves into the main doc tree
// so we'll no longer be able to get the siblings in the doc frag.
nsCOMPtr<nsIDOMNode> nextSib;
child->GetNextSibling(getter_AddRefs(nextSib));
// Ignore the return value, we'll check child when we loop around again.
// Now we can insert the node.
res = InsertNode(child, parentNode, offsetOfNewNode++);
if (NS_FAILED(res))
break;
child = nextSib;
}
if (NS_FAILED(res))
return res;
// Now collapse the selection to the end of what we just inserted:
selection->Collapse(parentNode, offsetOfNewNode);
}
if (NS_FAILED(res))
return res;
// Now collapse the selection to the end of what we just inserted:
selection->Collapse(parentNode, offsetOfNewNode);
res = mRules->DidDoAction(selection, &ruleInfo, res);
return res;
}

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

@ -242,7 +242,42 @@ nsTextEditRules::WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel)
mBogusNode = do_QueryInterface(nsnull);
}
return NS_OK;
// this next only works for collapsed selections right now,
// because selection is a pain to work with when not collapsed.
// (no good way to extend start or end of selection)
PRBool bCollapsed;
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
if (NS_FAILED(res)) return res;
if (!bCollapsed) return NS_OK;
// if we are after a mozBR in the same block, then move selection
// to be before it
nsCOMPtr<nsIDOMNode> selNode, priorNode;
PRInt32 selOffset;
// get the (collapsed) selection location
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
// get next node
res = GetPriorHTMLNode(selNode, selOffset, &priorNode);
if (NS_SUCCEEDED(res) && priorNode && IsMozBR(priorNode))
{
nsCOMPtr<nsIDOMNode> block1, block2;
if (mEditor->IsBlockNode(selNode)) block1 = selNode;
else block1 = mEditor->GetBlockNodeParent(selNode);
block2 = mEditor->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, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
res = aSelection->Collapse(selNode,selOffset);
if (NS_FAILED(res)) return res;
}
return res;
}
nsresult
@ -291,7 +326,26 @@ nsTextEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
if (mFlags & nsIHTMLEditor::eEditorSingleLineMask) {
*aCancel = PR_TRUE;
}
else {
else
{
*aCancel = PR_FALSE;
// if the selection isn't collapsed, delete it.
PRBool bCollapsed;
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
if (NS_FAILED(res)) return res;
if (!bCollapsed)
{
res = mEditor->DeleteSelection(nsIEditor::eDoNothing);
if (NS_FAILED(res)) return res;
}
res = WillInsert(aSelection, aCancel);
if (NS_FAILED(res)) return res;
// initialize out param
// we want to ignore result of WillInsert()
*aCancel = PR_FALSE;
// Mail rule: split any <pre> tags in the way,
// since they're probably quoted text.
// For now, do this for all plaintext since mail is our main customer
@ -300,7 +354,6 @@ nsTextEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
{
nsCOMPtr<nsIDOMNode> preNode, selNode;
PRInt32 selOffset, newOffset;
nsresult res;
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
@ -317,9 +370,7 @@ nsTextEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
res = aSelection->Collapse(selNode, newOffset);
}
}
}
*aCancel = PR_FALSE;
}
}
return NS_OK;
}
@ -327,7 +378,53 @@ nsTextEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
nsresult
nsTextEditRules::DidInsertBreak(nsIDOMSelection *aSelection, nsresult aResult)
{
return NS_OK;
// if we are at the end of the document, we need to insert
// a special mozBR following the normal br, and then set the
// selection to after the mozBR.
PRInt32 selOffset;
nsCOMPtr<nsIDOMNode> nearNode, selNode;
nsresult res;
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
res = GetPriorHTMLNode(selNode, selOffset, &nearNode);
if (NS_FAILED(res)) return res;
if (nearNode && IsBreak(nearNode) && !IsMozBR(nearNode))
{
PRBool bIsLast;
res = IsLastEditableChild(nearNode, &bIsLast);
if (NS_FAILED(res)) return res;
if (bIsLast)
{
// need to insert special moz BR. Why? Because if we don't
// the user will see no new line for the break. Also, things
// like table cells won't grow in height.
nsCOMPtr<nsIDOMNode> brNode;
res = CreateMozBR(selNode, selOffset, &brNode);
if (NS_FAILED(res)) return res;
res = nsEditor::GetNodeLocation(brNode, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
res = aSelection->Collapse(selNode,selOffset+1);
if (NS_FAILED(res)) return res;
}
else
{
// ok, the br inst the last child. But it might be second-to-last
// with a mozBR already exiting after it. In this case we have to
// move the selection to after the mozBR so it will show up on the
// empty line.
nsCOMPtr<nsIDOMNode> nextNode;
res = GetNextHTMLNode(nearNode, &nextNode);
if (NS_FAILED(res)) return res;
if (IsMozBR(nextNode))
{
res = nsEditor::GetNodeLocation(nextNode, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
res = aSelection->Collapse(selNode,selOffset+1);
if (NS_FAILED(res)) return res;
}
}
}
return res;
}
nsresult
@ -361,6 +458,23 @@ nsTextEditRules::WillInsertText(nsIDOMSelection *aSelection,
if (NS_FAILED(res)) return res;
}
// if the selection isn't collapsed, delete it.
PRBool bCollapsed;
res = aSelection->GetIsCollapsed(&bCollapsed);
if (NS_FAILED(res)) return res;
if (!bCollapsed)
{
res = mEditor->DeleteSelection(nsIEditor::eDoNothing);
if (NS_FAILED(res)) return res;
}
res = WillInsert(aSelection, aCancel);
if (NS_FAILED(res)) return res;
// initialize out param
// we want to ignore result of WillInsert()
*aCancel = PR_FALSE;
// do text insertion
PRBool bCancel;
res = DoTextInsertion(aSelection, &bCancel, aOutString, aTypeInState);
@ -1246,3 +1360,354 @@ nsTextEditRules::DoTextInsertion(nsIDOMSelection *aSelection,
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetPriorHTMLSibling: returns the previous editable sibling, if there is
// one within the parent
//
nsresult
nsTextEditRules::GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = NS_OK;
*outNode = nsnull;
nsCOMPtr<nsIDOMNode> temp, node = do_QueryInterface(inNode);
while (1)
{
res = node->GetPreviousSibling(getter_AddRefs(temp));
if (NS_FAILED(res)) return res;
if (!temp) return NS_ERROR_FAILURE;
// if it's editable, we're done
if (mEditor->IsEditable(temp)) break;
// otherwise try again
node = temp;
}
*outNode = temp;
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetNextHTMLSibling: returns the next editable sibling, if there is
// one within the parent
//
nsresult
nsTextEditRules::GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = NS_OK;
*outNode = nsnull;
nsCOMPtr<nsIDOMNode> temp, node = do_QueryInterface(inNode);
while (1)
{
res = node->GetNextSibling(getter_AddRefs(temp));
if (NS_FAILED(res)) return res;
if (!temp) return NS_ERROR_FAILURE;
// if it's editable, we're done
if (mEditor->IsEditable(temp)) break;
// otherwise try again
node = temp;
}
*outNode = temp;
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetPriorHTMLNode: returns the previous editable leaf node, if there is
// one within the <body>
//
nsresult
nsTextEditRules::GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->GetPriorNode(inNode, PR_TRUE, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// if it's not in the body, then zero it out
if (*outNode && !InBody(*outNode))
{
*outNode = nsnull;
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetPriorHTMLNode: same as above but takes {parent,offset} instead of node
//
nsresult
nsTextEditRules::GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->GetPriorNode(inParent, inOffset, PR_TRUE, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// if it's not in the body, then zero it out
if (*outNode && !InBody(*outNode))
{
*outNode = nsnull;
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetNextHTMLNode: returns the previous editable leaf node, if there is
// one within the <body>
//
nsresult
nsTextEditRules::GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->GetNextNode(inNode, PR_TRUE, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// if it's not in the body, then zero it out
if (*outNode && !InBody(*outNode))
{
*outNode = nsnull;
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetNHTMLextNode: same as above but takes {parent,offset} instead of node
//
nsresult
nsTextEditRules::GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->GetNextNode(inParent, inOffset, PR_TRUE, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// if it's not in the body, then zero it out
if (*outNode && !InBody(*outNode))
{
*outNode = nsnull;
}
return res;
}
nsresult
nsTextEditRules::IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst)
{
// check parms
if (!aOutIsFirst || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutIsFirst = PR_FALSE;
// find first editable child and compare it to aNode
nsCOMPtr<nsIDOMNode> parent, firstChild;
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
if (!parent) return NS_ERROR_FAILURE;
res = GetFirstEditableChild(parent, &firstChild);
if (NS_FAILED(res)) return res;
*aOutIsFirst = (firstChild.get() == aNode);
return res;
}
nsresult
nsTextEditRules::IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast)
{
// check parms
if (!aOutIsLast || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutIsLast = PR_FALSE;
// find last editable child and compare it to aNode
nsCOMPtr<nsIDOMNode> parent, lastChild;
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
if (!parent) return NS_ERROR_FAILURE;
res = GetLastEditableChild(parent, &lastChild);
if (NS_FAILED(res)) return res;
*aOutIsLast = (lastChild.get() == aNode);
return res;
}
nsresult
nsTextEditRules::GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild)
{
// check parms
if (!aOutFirstChild || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutFirstChild = nsnull;
// find first editable child
nsCOMPtr<nsIDOMNode> child;
nsresult res = aNode->GetFirstChild(getter_AddRefs(child));
if (NS_FAILED(res)) return res;
while (child && !mEditor->IsEditable(child))
{
nsCOMPtr<nsIDOMNode> tmp;
res = child->GetNextSibling(getter_AddRefs(tmp));
if (NS_FAILED(res)) return res;
if (!tmp) return NS_ERROR_FAILURE;
child = tmp;
}
*aOutFirstChild = child;
return res;
}
nsresult
nsTextEditRules::GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild)
{
// check parms
if (!aOutLastChild || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutLastChild = nsnull;
// find last editable child
nsCOMPtr<nsIDOMNode> child;
nsresult res = aNode->GetLastChild(getter_AddRefs(child));
if (NS_FAILED(res)) return res;
while (child && !mEditor->IsEditable(child))
{
nsCOMPtr<nsIDOMNode> tmp;
res = child->GetPreviousSibling(getter_AddRefs(tmp));
if (NS_FAILED(res)) return res;
if (!tmp) return NS_ERROR_FAILURE;
child = tmp;
}
*aOutLastChild = child;
return res;
}
///////////////////////////////////////////////////////////////////////////
// IsBody: true if node an html body node
//
PRBool
nsTextEditRules::IsBody(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null node passed to nsTextEditRules::IsBody");
nsAutoString tag;
nsEditor::GetTagString(node,tag);
tag.ToLowerCase();
if (tag == "body")
{
return PR_TRUE;
}
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsBreak: true if node an html break node
//
PRBool
nsTextEditRules::IsBreak(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null node passed to nsTextEditRules::IsBreak");
nsAutoString tag;
nsEditor::GetTagString(node,tag);
tag.ToLowerCase();
if (tag == "br")
{
return PR_TRUE;
}
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsMozBR: true if node an html br node with type = _moz
//
PRBool
nsTextEditRules::IsMozBR(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null node passed to nsTextEditRules::IsMozBR");
if (IsBreak(node) && HasMozAttr(node)) return PR_TRUE;
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// HasMozAttr: true if node has type attribute = _moz
// (used to indicate the div's and br's we use in
// mail compose rules)
//
PRBool
nsTextEditRules::HasMozAttr(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null parent passed to nsTextEditRules::HasMozAttr");
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(node);
if (elem)
{
nsAutoString typeAttrName("type");
nsAutoString typeAttrVal;
nsresult res = elem->GetAttribute(typeAttrName, typeAttrVal);
typeAttrVal.ToLowerCase();
if (NS_SUCCEEDED(res) && (typeAttrVal == "_moz"))
return PR_TRUE;
}
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// InBody: true if node is a descendant of the body
//
PRBool
nsTextEditRules::InBody(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null parent passed to nsTextEditRules::InBody");
nsCOMPtr<nsIDOMNode> tmp;
nsCOMPtr<nsIDOMNode> p = do_QueryInterface(node);
while (p && !IsBody(p))
{
if ( NS_FAILED(p->GetParentNode(getter_AddRefs(tmp))) || !tmp) // no parent, ran off top of tree
return PR_FALSE;
p = tmp;
}
if (p) return PR_TRUE;
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// CreateMozBR: put a BR node with moz attribute at {aNode, aOffset}
//
nsresult
nsTextEditRules::CreateMozBR(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outBRNode)
{
if (!inParent || !outBRNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->CreateBR(inParent, inOffset, outBRNode);
if (NS_FAILED(res)) return res;
// give it special moz attr
nsCOMPtr<nsIDOMElement> brElem = do_QueryInterface(*outBRNode);
if (brElem)
{
res = mEditor->SetAttribute(brElem, "type", "_moz");
if (NS_FAILED(res)) return res;
}
return res;
}

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

@ -200,6 +200,28 @@ protected:
const nsString *aInString,
TypeInState aTypeInState);
nsresult GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
nsresult IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst);
nsresult IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast);
nsresult GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild);
nsresult GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild);
static PRBool IsBody(nsIDOMNode *aNode);
static PRBool IsBreak(nsIDOMNode *aNode);
static PRBool IsMozBR(nsIDOMNode *aNode);
static PRBool HasMozAttr(nsIDOMNode *aNode);
static PRBool InBody(nsIDOMNode *aNode);
nsresult CreateMozBR(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outBRNode);
// data
nsHTMLEditor *mEditor; // note that we do not refcount the editor
nsString mPasswordText; // a buffer we use to store the real value of password editors

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

@ -88,6 +88,26 @@ nsHTMLEditRules::Init(nsHTMLEditor *aEditor, PRUint32 aFlags)
nsresult res = nsTextEditRules::Init(aEditor, aFlags);
if (NS_FAILED(res)) return res;
// pass over document and add any needed mozBRs
// first turn off undo
mEditor->EnableUndo(PR_FALSE);
// set up mDocChangeRange to be whole doc
nsCOMPtr<nsIDOMElement> bodyElem;
nsCOMPtr<nsIDOMNode> bodyNode;
mEditor->GetBodyElement(getter_AddRefs(bodyElem));
bodyNode = do_QueryInterface(bodyElem);
if (bodyNode)
{
res = nsComponentManager::CreateInstance(kRangeCID, nsnull, nsIDOMRange::GetIID(),
getter_AddRefs(mDocChangeRange));
if (NS_FAILED(res)) return res;
if (!mDocChangeRange) return NS_ERROR_NULL_POINTER;
mDocChangeRange->SelectNode(bodyNode);
AdjustSpecialBreaks();
}
// turn on undo
mEditor->EnableUndo(PR_TRUE);
// make a listener
res = NS_NewEditListener(getter_AddRefs(mListener), mEditor, this);
if (NS_FAILED(res)) return res;
@ -198,8 +218,11 @@ nsHTMLEditRules::DidDoAction(nsIDOMSelection *aSelection,
}
// do default:
res = nsTextEditRules::DidDoAction(aSelection, aInfo, aResult);
if (NS_FAILED(res)) return res;
if (aInfo->action != kInsertBreak) // nsTextEditRules::DidInsertBreak() not usable by html rules
{
res = nsTextEditRules::DidDoAction(aSelection, aInfo, aResult);
if (NS_FAILED(res)) return res;
}
// adjust selection
res = AdjustSelection(aSelection,info->collapsedAction);
return res;
@ -211,52 +234,6 @@ nsHTMLEditRules::DidDoAction(nsIDOMSelection *aSelection,
********************************************************/
nsresult
nsHTMLEditRules::WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel)
{
if (!aSelection || !aCancel)
return NS_ERROR_NULL_POINTER;
nsresult res = nsTextEditRules::WillInsert(aSelection, aCancel);
if (NS_FAILED(res)) return res;
// this next only works for collapsed selections right now,
// because selection is a pain to work with when not collapsed.
// (no good way to extend start or end of selection)
PRBool bCollapsed;
res = aSelection->GetIsCollapsed(&bCollapsed);
if (NS_FAILED(res)) return res;
if (!bCollapsed) return NS_OK;
// if we are after a mozBR in the same block, then move selection
// to be before it
nsCOMPtr<nsIDOMNode> selNode, priorNode;
PRInt32 selOffset;
// get the (collapsed) selection location
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
// get prior node
nsCOMPtr<nsIDOMNode> block1, block2;
if (mEditor->IsBlockNode(selNode)) block1 = selNode;
else block1 = mEditor->GetBlockNodeParent(selNode);
if (mEditor->IsBlockNode(priorNode)) block2 = priorNode;
else block2 = mEditor->GetBlockNodeParent(priorNode);
if (block1 != block2) return NS_OK;
if (!IsMozBR(priorNode)) 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, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
res = aSelection->Collapse(selNode,selOffset);
if (NS_FAILED(res)) return res;
return NS_OK;
}
nsresult
nsHTMLEditRules::WillInsertText(PRInt32 aAction,
nsIDOMSelection *aSelection,
@ -266,7 +243,8 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
nsString *outString,
TypeInState typeInState,
PRInt32 aMaxLength)
{ if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
{
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
// initialize out param
*aCancel = PR_FALSE;
@ -332,19 +310,6 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
// find a nearby text node if possible
nsCOMPtr<nsIDOMNode> priorNode, nextNode;
res = GetPriorHTMLNode(selNode, selOffset, &priorNode);
// are we after a mozBR?
if (NS_SUCCEEDED(res) && priorNode && IsMozBR(priorNode)
&& (blockParent == mEditor->GetBlockNodeParent(priorNode)))
{
// uhh, lets be before it instead of after it. Now
// walk away reeeal slow...
res = nsEditor::GetNodeLocation(priorNode, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
res = aSelection->Collapse(selNode, selOffset);
if (NS_FAILED(res)) return res;
// we know we are still not in a text node, so fall through to rest of this case
res = GetPriorHTMLNode(selNode, selOffset, &priorNode);
}
if (NS_SUCCEEDED(res) && priorNode && mEditor->IsTextNode(priorNode)
&& (blockParent == mEditor->GetBlockNodeParent(priorNode)))
{
@ -464,17 +429,10 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
*aCancel = PR_FALSE;
*aHandled = PR_FALSE;
nsresult res;
res = WillInsert(aSelection, aCancel);
if (NS_FAILED(res)) return res;
// initialize out param
// we want to ignore result of WillInsert()
*aCancel = PR_FALSE;
// if the selection isn't collapsed, delete it.
PRBool bCollapsed;
res = aSelection->GetIsCollapsed(&bCollapsed);
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
if (NS_FAILED(res)) return res;
if (!bCollapsed)
{
@ -482,6 +440,14 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
if (NS_FAILED(res)) return res;
}
res = WillInsert(aSelection, aCancel);
if (NS_FAILED(res)) return res;
// initialize out param
// we want to ignore result of WillInsert()
*aCancel = PR_FALSE;
// split any mailcites in the way
if (mFlags & nsIHTMLEditor::eEditorMailMask)
{
@ -592,23 +558,6 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
// its something else (body, div, td, ...): insert a normal br
else
{
nsCOMPtr<nsIDOMNode> nearNode;
res = GetPriorHTMLNode(node, offset, &nearNode);
if (NS_FAILED(res)) return res;
if (nearNode && IsBreak(nearNode) && IsMozBR(nearNode))
{
// is nearNode also a descendant of same block?
nsCOMPtr<nsIDOMNode> nearBlock = mEditor->GetBlockNodeParent(nearNode);
if (blockParent == nearBlock)
{
// need to insert special BEFORE the moz BR. Why? Because if we don't
// the selectin adjusting code will add an extra BR. doh.
res = nsEditor::GetNodeLocation(nearNode, &node, &offset);
if (NS_FAILED(res)) return res;
res = aSelection->Collapse(node, offset);
if (NS_FAILED(res)) return res;
}
}
nsCOMPtr<nsIDOMNode> brNode;
res = mEditor->CreateBR(node, offset, &brNode);
if (NS_FAILED(res)) return res;
@ -1830,42 +1779,6 @@ nsHTMLEditRules::IsUnorderedList(nsIDOMNode *node)
}
///////////////////////////////////////////////////////////////////////////
// IsBreak: true if node an html break node
//
PRBool
nsHTMLEditRules::IsBreak(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsBreak");
nsAutoString tag;
nsEditor::GetTagString(node,tag);
tag.ToLowerCase();
if (tag == "br")
{
return PR_TRUE;
}
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsBody: true if node an html body node
//
PRBool
nsHTMLEditRules::IsBody(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsBody");
nsAutoString tag;
nsEditor::GetTagString(node,tag);
tag.ToLowerCase();
if (tag == "body")
{
return PR_TRUE;
}
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsBlockquote: true if node an html blockquote node
//
@ -1942,39 +1855,6 @@ nsHTMLEditRules::IsMozDiv(nsIDOMNode *node)
}
///////////////////////////////////////////////////////////////////////////
// IsMozBR: true if node an html br node with type = _moz
//
PRBool
nsHTMLEditRules::IsMozBR(nsIDOMNode *node)
{
if (IsBreak(node) && HasMozAttr(node)) return PR_TRUE;
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// HasMozAttr: true if node has type attribute = _moz
// (used to indicate the div's and br's we use in
// mail compose rules)
//
PRBool
nsHTMLEditRules::HasMozAttr(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::HasMozAttr");
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(node);
if (elem)
{
nsAutoString typeAttrName("type");
nsAutoString typeAttrVal;
nsresult res = elem->GetAttribute(typeAttrName, typeAttrVal);
typeAttrVal.ToLowerCase();
if (NS_SUCCEEDED(res) && (typeAttrVal == "_moz"))
return PR_TRUE;
}
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsMailCite: true if node an html blockquote with type=cite
@ -2000,26 +1880,6 @@ nsHTMLEditRules::IsMailCite(nsIDOMNode *node)
}
///////////////////////////////////////////////////////////////////////////
// InBody: true if node is a descendant of the body
//
PRBool
nsHTMLEditRules::InBody(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::InBody");
nsCOMPtr<nsIDOMNode> tmp;
nsCOMPtr<nsIDOMNode> p = do_QueryInterface(node);
while (p && !IsBody(p))
{
if ( NS_FAILED(p->GetParentNode(getter_AddRefs(tmp))) || !tmp) // no parent, ran off top of tree
return PR_FALSE;
p = tmp;
}
if (p) return PR_TRUE;
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsEmptyBlock: figure out if aNode is (or is inside) an empty block.
// A block can have children and still be considered empty,
@ -2181,143 +2041,6 @@ nsHTMLEditRules::CreateMozDiv(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<n
}
#endif
///////////////////////////////////////////////////////////////////////////
// GetPriorHTMLSibling: returns the previous editable sibling, if there is
// one within the parent
//
nsresult
nsHTMLEditRules::GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = NS_OK;
*outNode = nsnull;
nsCOMPtr<nsIDOMNode> temp, node = do_QueryInterface(inNode);
while (1)
{
res = node->GetPreviousSibling(getter_AddRefs(temp));
if (NS_FAILED(res)) return res;
if (!temp) return NS_ERROR_FAILURE;
// if it's editable, we're done
if (mEditor->IsEditable(temp)) break;
// otherwise try again
node = temp;
}
*outNode = temp;
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetNextHTMLSibling: returns the next editable sibling, if there is
// one within the parent
//
nsresult
nsHTMLEditRules::GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = NS_OK;
*outNode = nsnull;
nsCOMPtr<nsIDOMNode> temp, node = do_QueryInterface(inNode);
while (1)
{
res = node->GetNextSibling(getter_AddRefs(temp));
if (NS_FAILED(res)) return res;
if (!temp) return NS_ERROR_FAILURE;
// if it's editable, we're done
if (mEditor->IsEditable(temp)) break;
// otherwise try again
node = temp;
}
*outNode = temp;
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetPriorHTMLNode: returns the previous editable leaf node, if there is
// one within the <body>
//
nsresult
nsHTMLEditRules::GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->GetPriorNode(inNode, PR_TRUE, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// if it's not in the body, then zero it out
if (*outNode && !InBody(*outNode))
{
*outNode = nsnull;
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetPriorHTMLNode: same as above but takes {parent,offset} instead of node
//
nsresult
nsHTMLEditRules::GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->GetPriorNode(inParent, inOffset, PR_TRUE, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// if it's not in the body, then zero it out
if (*outNode && !InBody(*outNode))
{
*outNode = nsnull;
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetNextHTMLNode: returns the previous editable leaf node, if there is
// one within the <body>
//
nsresult
nsHTMLEditRules::GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->GetNextNode(inNode, PR_TRUE, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// if it's not in the body, then zero it out
if (*outNode && !InBody(*outNode))
{
*outNode = nsnull;
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetNHTMLextNode: same as above but takes {parent,offset} instead of node
//
nsresult
nsHTMLEditRules::GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->GetNextNode(inParent, inOffset, PR_TRUE, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// if it's not in the body, then zero it out
if (*outNode && !InBody(*outNode))
{
*outNode = nsnull;
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetTabAsNBSPs: stuff the right number of nbsp's into outString
//
@ -2352,17 +2075,27 @@ nsHTMLEditRules::IsFirstNode(nsIDOMNode *aNode)
{
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset, j=0;
nsEditor::GetNodeLocation(aNode, &parent, &offset);
nsresult res = nsEditor::GetNodeLocation(aNode, &parent, &offset);
if (NS_FAILED(res))
{
NS_NOTREACHED("failure in nsHTMLEditRules::IsFirstNode");
return PR_FALSE;
}
if (!offset) // easy case, we are first dom child
return PR_TRUE;
if (!parent)
return PR_TRUE;
// ok, so there are earlier children. But are they editable???
nsCOMPtr<nsIDOMNodeList>childList;
nsCOMPtr<nsIDOMNode> child;
if (!parent) return PR_TRUE;
parent->GetChildNodes(getter_AddRefs(childList));
res = parent->GetChildNodes(getter_AddRefs(childList));
if (NS_FAILED(res) || !childList)
{
NS_NOTREACHED("failure in nsHTMLEditRules::IsFirstNode");
return PR_TRUE;
}
while (j < offset)
{
childList->Item(j, getter_AddRefs(child));
@ -2383,16 +2116,28 @@ nsHTMLEditRules::IsLastNode(nsIDOMNode *aNode)
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset, j;
PRUint32 numChildren;
nsEditor::GetNodeLocation(aNode, &parent, &offset);
nsresult res = nsEditor::GetNodeLocation(aNode, &parent, &offset);
if (NS_FAILED(res))
{
NS_NOTREACHED("failure in nsHTMLEditRules::IsLastNode");
return PR_FALSE;
}
nsEditor::GetLengthOfDOMNode(parent, numChildren);
if (offset+1 == (PRInt32)numChildren) // easy case, we are last dom child
return PR_TRUE;
if (!parent)
return PR_TRUE;
// ok, so there are later children. But are they editable???
j = offset+1;
nsCOMPtr<nsIDOMNodeList>childList;
nsCOMPtr<nsIDOMNode> child;
parent->GetChildNodes(getter_AddRefs(childList));
res = parent->GetChildNodes(getter_AddRefs(childList));
if (NS_FAILED(res) || !childList)
{
NS_NOTREACHED("failure in nsHTMLEditRules::IsLastNode");
return PR_TRUE;
}
while (j < (PRInt32)numChildren)
{
childList->Item(j, getter_AddRefs(child));
@ -2434,7 +2179,7 @@ nsHTMLEditRules::AtEndOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aB
{
PRUint32 strLength;
nodeAsText->GetLength(&strLength);
if (strLength > aOffset) return PR_FALSE; // there are chars in after us
if ((PRInt32)strLength > aOffset) return PR_FALSE; // there are chars in after us
}
nsCOMPtr<nsIDOMNode> nextNode;
nsresult res = GetNextHTMLNode(aNode, aOffset, &nextNode);
@ -2549,7 +2294,7 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt
// finding the real start for this point. look up the tree for as long as we are the
// first node in the container, and as long as we haven't hit the body node.
nsEditor::GetNodeLocation(node, &parent, &offset);
res = nsEditor::GetNodeLocation(node, &parent, &offset);
if (NS_FAILED(res)) return res;
while ((IsFirstNode(node)) && (!IsBody(parent)))
{
@ -2567,7 +2312,8 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt
// some special casing for text nodes
if (nsEditor::IsTextNode(aNode))
{
nsEditor::GetNodeLocation(aNode, &parent, &offset);
res = nsEditor::GetNodeLocation(aNode, &parent, &offset);
if (NS_FAILED(res)) return res;
}
else
{
@ -2608,7 +2354,7 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt
// finding the real end for this point. look up the tree for as long as we are the
// last node in the container, and as long as we haven't hit the body node.
nsEditor::GetNodeLocation(node, &parent, &offset);
res = nsEditor::GetNodeLocation(node, &parent, &offset);
if (NS_FAILED(res)) return res;
while ((IsLastNode(node)) && (!IsBody(parent)))
{
@ -2782,6 +2528,7 @@ nsHTMLEditRules::GetChildNodesForOperation(nsIDOMNode *inNode,
nsCOMPtr<nsIDOMNodeList> childNodes;
res = inNode->GetChildNodes(getter_AddRefs(childNodes));
if (NS_FAILED(res)) return res;
if (!childNodes) return NS_ERROR_NULL_POINTER;
PRUint32 childCount;
res = childNodes->GetLength(&childCount);
if (NS_FAILED(res)) return res;
@ -3070,27 +2817,6 @@ nsHTMLEditRules::InsertSpace(nsIDOMSelection *aSelection,
}
///////////////////////////////////////////////////////////////////////////
// CreateMozBR: put a BR node with moz attribute at {aNode, aOffset}
//
nsresult
nsHTMLEditRules::CreateMozBR(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outBRNode)
{
if (!inParent || !outBRNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->CreateBR(inParent, inOffset, outBRNode);
if (NS_FAILED(res)) return res;
// give it special moz attr
nsCOMPtr<nsIDOMElement> brElem = do_QueryInterface(*outBRNode);
if (brElem)
{
res = mEditor->SetAttribute(brElem, "type", "_moz");
if (NS_FAILED(res)) return res;
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// ReturnInHeader: do the right thing for returns pressed in headers
//
@ -3186,7 +2912,7 @@ nsHTMLEditRules::ReturnInParagraph(nsIDOMSelection *aSelection,
return res;
}
// at end of text node?
if (aOffset == strLength)
if (aOffset == (PRInt32)strLength)
{
// is there a BR after to it?
res = GetNextHTMLSibling(aNode, &sibling);
@ -3300,7 +3026,7 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,
{
// time to insert a break
nsCOMPtr<nsIDOMNode> brNode;
nsresult res = CreateMozBR(selNode, selOffset, &brNode);
res = CreateMozBR(selNode, selOffset, &brNode);
if (NS_FAILED(res)) return res;
res = nsEditor::GetNodeLocation(brNode, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
@ -3591,104 +3317,6 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString
}
nsresult
nsHTMLEditRules::IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst)
{
// check parms
if (!aOutIsFirst || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutIsFirst = PR_FALSE;
// find first editable child and compare it to aNode
nsCOMPtr<nsIDOMNode> parent, firstChild;
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
if (!parent) return NS_ERROR_FAILURE;
res = GetFirstEditableChild(parent, &firstChild);
if (NS_FAILED(res)) return res;
*aOutIsFirst = (firstChild.get() == aNode);
return res;
}
nsresult
nsHTMLEditRules::IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast)
{
// check parms
if (!aOutIsLast || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutIsLast = PR_FALSE;
// find last editable child and compare it to aNode
nsCOMPtr<nsIDOMNode> parent, lastChild;
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
if (!parent) return NS_ERROR_FAILURE;
res = GetLastEditableChild(parent, &lastChild);
if (NS_FAILED(res)) return res;
*aOutIsLast = (lastChild.get() == aNode);
return res;
}
nsresult
nsHTMLEditRules::GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild)
{
// check parms
if (!aOutFirstChild || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutFirstChild = nsnull;
// find first editable child
nsCOMPtr<nsIDOMNode> child;
nsresult res = aNode->GetFirstChild(getter_AddRefs(child));
if (NS_FAILED(res)) return res;
while (child && !mEditor->IsEditable(child))
{
nsCOMPtr<nsIDOMNode> tmp;
res = child->GetNextSibling(getter_AddRefs(tmp));
if (NS_FAILED(res)) return res;
if (!tmp) return NS_ERROR_FAILURE;
child = tmp;
}
*aOutFirstChild = child;
return res;
}
nsresult
nsHTMLEditRules::GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild)
{
// check parms
if (!aOutLastChild || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutLastChild = nsnull;
// find last editable child
nsCOMPtr<nsIDOMNode> child;
nsresult res = aNode->GetLastChild(getter_AddRefs(child));
if (NS_FAILED(res)) return res;
while (child && !mEditor->IsEditable(child))
{
nsCOMPtr<nsIDOMNode> tmp;
res = child->GetPreviousSibling(getter_AddRefs(tmp));
if (NS_FAILED(res)) return res;
if (!tmp) return NS_ERROR_FAILURE;
child = tmp;
}
*aOutLastChild = child;
return res;
}
///////////////////////////////////////////////////////////////////////////
@ -3846,7 +3474,7 @@ nsHTMLEditRules::AdjustSpecialBreaks()
// put moz-br's into these empty li's and td's
res = arrayOfNodes->Count(&nodeCount);
if (NS_FAILED(res)) return res;
for (j = 0; j < (PRInt32)nodeCount; j++)
for (j = 0; j < nodeCount; j++)
{
isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
nsCOMPtr<nsIDOMNode> brNode, theNode( do_QueryInterface(isupports ) );
@ -3929,7 +3557,7 @@ nsHTMLEditRules::AdjustWhitespace()
// now adjust whitespace on node we found
res = arrayOfNodes->Count(&nodeCount);
if (NS_FAILED(res)) return res;
for (j = 0; j < (PRInt32)nodeCount; j++)
for (j = 0; j < nodeCount; j++)
{
isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
nsCOMPtr<nsIDOMCharacterData> textNode( do_QueryInterface(isupports ) );
@ -3968,7 +3596,7 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::ESelect
// do we need to insert a special mozBR? We do if we are:
// 1) in a collapsed selection AND
// 2) after a normal (non-moz) br AND
// 3) that br in the last editable node in it's block AND
// 3) that br is the last editable node in it's block AND
// 4) that block is same block where selection is
nsCOMPtr<nsIDOMNode> nearNode;
res = GetPriorHTMLNode(selNode, selOffset, &nearNode);
@ -4103,7 +3731,7 @@ nsHTMLEditRules::RemoveEmptyNodes()
// now delete the empty nodes
res = arrayOfNodes->Count(&nodeCount);
if (NS_FAILED(res)) return res;
for (j = 0; j < (PRInt32)nodeCount; j++)
for (j = 0; j < nodeCount; j++)
{
isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
nsCOMPtr<nsIDOMNode> delNode( do_QueryInterface(isupports ) );

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

@ -55,7 +55,6 @@ protected:
// nsHTMLEditRules implementation methods
nsresult WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel);
nsresult WillInsertText( PRInt32 aAction,
nsIDOMSelection *aSelection,
PRBool *aCancel,
@ -92,18 +91,13 @@ protected:
static PRBool IsList(nsIDOMNode *aNode);
static PRBool IsUnorderedList(nsIDOMNode *aNode);
static PRBool IsOrderedList(nsIDOMNode *aNode);
static PRBool IsBreak(nsIDOMNode *aNode);
static PRBool IsBody(nsIDOMNode *aNode);
static PRBool IsBlockquote(nsIDOMNode *aNode);
static PRBool IsAnchor(nsIDOMNode *aNode);
static PRBool IsDiv(nsIDOMNode *aNode);
static PRBool IsNormalDiv(nsIDOMNode *aNode);
static PRBool IsMozDiv(nsIDOMNode *aNode);
static PRBool IsMozBR(nsIDOMNode *aNode);
static PRBool IsMailCite(nsIDOMNode *aNode);
static PRBool HasMozAttr(nsIDOMNode *aNode);
static PRBool InBody(nsIDOMNode *aNode);
nsresult IsEmptyBlock(nsIDOMNode *aNode,
PRBool *outIsEmptyBlock,
@ -118,15 +112,7 @@ protected:
PRBool IsLastNode(nsIDOMNode *aNode);
PRBool AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock);
PRBool AtEndOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock);
nsresult CreateMozBR(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outBRNode);
nsresult GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt32 aOffset,
PRInt32 actionID, nsCOMPtr<nsIDOMNode> *outNode, PRInt32 *outOffset);
nsresult GetPromotedRanges(nsIDOMSelection *inSelection,
@ -148,11 +134,6 @@ protected:
nsresult RemoveContainer(nsIDOMNode *inNode);
nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, const nsString &aNodeType);
nsresult IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst);
nsresult IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast);
nsresult GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild);
nsresult GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild);
nsresult JoinNodesSmart( nsIDOMNode *aNodeLeft,
nsIDOMNode *aNodeRight,
nsCOMPtr<nsIDOMNode> *aOutMergeParent,

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

@ -390,12 +390,6 @@ NS_IMETHODIMP nsHTMLEditor::Init(nsIDOMDocument *aDoc,
}
}
// Init the rules system
// XXX: ERROR CHECKING should InitRules return an error, and then we could check it here?
InitRules();
EnableUndo(PR_TRUE);
// Set up a DTD XXX XXX
// HACK: This should have happened in a document specific way
// in nsEditor::Init(), but we dont' have a way to do that yet
@ -403,6 +397,12 @@ NS_IMETHODIMP nsHTMLEditor::Init(nsIDOMDocument *aDoc,
nsIDTD::GetIID(), getter_AddRefs(mDTD));
if (!mDTD) result = NS_ERROR_FAILURE;
// Init the rules system
// XXX: ERROR CHECKING should InitRules return an error, and then we could check it here?
InitRules();
EnableUndo(PR_TRUE);
return result;
}
@ -1349,97 +1349,99 @@ NS_IMETHODIMP nsHTMLEditor::InsertHTML(const nsString& aInputString)
nsCOMPtr<nsIDOMSelection>selection;
// Call the rules code in case there's anything we need to do first
// (e.g. delete the bogus node):
// Call the rules code in case there's anything we need to do first
// (e.g. delete the bogus node):
if (!mRules) return NS_ERROR_NOT_INITIALIZED;
res = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
nsTextRulesInfo ruleInfo(nsHTMLEditRules::kInsertElement);
PRBool cancel, handled;
res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMNode> parentNode;
PRInt32 offsetOfNewNode;
res = DeleteSelectionAndPrepareToCreateNode(parentNode, offsetOfNewNode);
if (NS_FAILED(res)) return res;
res = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
if (!selection) return NS_ERROR_NULL_POINTER;
// give rules a chance to handle or cancel
nsTextRulesInfo ruleInfo(nsHTMLEditRules::kInsertElement);
PRBool cancel, handled;
res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
if (NS_FAILED(res)) return res;
if (cancel) return NS_OK; // rules canceled the operation
if (!handled)
{
// Get the first range in the selection, for context:
nsCOMPtr<nsIDOMRange> range;
res = selection->GetRangeAt(0, getter_AddRefs(range));
if (NS_FAILED(res))
return res;
nsCOMPtr<nsIDOMNSRange> nsrange (do_QueryInterface(range));
if (!nsrange)
return NS_ERROR_NO_INTERFACE;
nsCOMPtr<nsIDOMDocumentFragment> docfrag;
res = nsrange->CreateContextualFragment(aInputString,
getter_AddRefs(docfrag));
if (NS_FAILED(res))
{
#ifdef DEBUG
printf("Couldn't create contextual fragment: error was %d\n", res);
#endif
return res;
}
#if defined(DEBUG_akkana_verbose)
printf("============ Fragment dump :===========\n");
nsCOMPtr<nsIContent> fragc (do_QueryInterface(docfrag));
if (!fragc)
printf("Couldn't get fragment is nsIContent\n");
else
fragc->List(stdout);
#endif
// Insert the contents of the document fragment:
nsCOMPtr<nsIDOMNode> fragmentAsNode (do_QueryInterface(docfrag));
// Loop over the contents of the fragment:
nsCOMPtr<nsIDOMNode> child;
res = fragmentAsNode->GetFirstChild(getter_AddRefs(child));
if (NS_FAILED(res))
{
printf("GetFirstChild failed!\n");
return res;
}
while (child)
{
#if defined(DEBUG_akkana_verbose)
printf("About to try to insert this node:\n");
nsCOMPtr<nsIContent> nodec (do_QueryInterface(child));
if (nodec) nodec->List(stdout);
printf("-----\n");
#endif
// Get the next sibling before inserting the node;
// when we insert the node, it moves into the main doc tree
// so we'll no longer be able to get the siblings in the doc frag.
nsCOMPtr<nsIDOMNode> nextSib;
child->GetNextSibling(getter_AddRefs(nextSib));
// Ignore the return value, we'll check child when we loop around again.
// Now we can insert the node.
res = InsertNode(child, parentNode, offsetOfNewNode++);
nsCOMPtr<nsIDOMRange> range;
res = selection->GetRangeAt(0, getter_AddRefs(range));
if (NS_FAILED(res))
break;
child = nextSib;
return res;
nsCOMPtr<nsIDOMNSRange> nsrange (do_QueryInterface(range));
if (!nsrange)
return NS_ERROR_NO_INTERFACE;
nsCOMPtr<nsIDOMDocumentFragment> docfrag;
res = nsrange->CreateContextualFragment(aInputString,
getter_AddRefs(docfrag));
if (NS_FAILED(res))
{
#ifdef DEBUG
printf("Couldn't create contextual fragment: error was %d\n", res);
#endif
return res;
}
#if defined(DEBUG_akkana_verbose)
printf("============ Fragment dump :===========\n");
nsCOMPtr<nsIContent> fragc (do_QueryInterface(docfrag));
if (!fragc)
printf("Couldn't get fragment is nsIContent\n");
else
fragc->List(stdout);
#endif
// Insert the contents of the document fragment:
nsCOMPtr<nsIDOMNode> fragmentAsNode (do_QueryInterface(docfrag));
// Loop over the contents of the fragment:
nsCOMPtr<nsIDOMNode> child;
res = fragmentAsNode->GetFirstChild(getter_AddRefs(child));
if (NS_FAILED(res))
{
printf("GetFirstChild failed!\n");
return res;
}
while (child)
{
#if defined(DEBUG_akkana_verbose)
printf("About to try to insert this node:\n");
nsCOMPtr<nsIContent> nodec (do_QueryInterface(child));
if (nodec) nodec->List(stdout);
printf("-----\n");
#endif
// Get the next sibling before inserting the node;
// when we insert the node, it moves into the main doc tree
// so we'll no longer be able to get the siblings in the doc frag.
nsCOMPtr<nsIDOMNode> nextSib;
child->GetNextSibling(getter_AddRefs(nextSib));
// Ignore the return value, we'll check child when we loop around again.
// Now we can insert the node.
res = InsertNode(child, parentNode, offsetOfNewNode++);
if (NS_FAILED(res))
break;
child = nextSib;
}
if (NS_FAILED(res))
return res;
// Now collapse the selection to the end of what we just inserted:
selection->Collapse(parentNode, offsetOfNewNode);
}
if (NS_FAILED(res))
return res;
// Now collapse the selection to the end of what we just inserted:
selection->Collapse(parentNode, offsetOfNewNode);
res = mRules->DidDoAction(selection, &ruleInfo, res);
return res;
}

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

@ -242,7 +242,42 @@ nsTextEditRules::WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel)
mBogusNode = do_QueryInterface(nsnull);
}
return NS_OK;
// this next only works for collapsed selections right now,
// because selection is a pain to work with when not collapsed.
// (no good way to extend start or end of selection)
PRBool bCollapsed;
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
if (NS_FAILED(res)) return res;
if (!bCollapsed) return NS_OK;
// if we are after a mozBR in the same block, then move selection
// to be before it
nsCOMPtr<nsIDOMNode> selNode, priorNode;
PRInt32 selOffset;
// get the (collapsed) selection location
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
// get next node
res = GetPriorHTMLNode(selNode, selOffset, &priorNode);
if (NS_SUCCEEDED(res) && priorNode && IsMozBR(priorNode))
{
nsCOMPtr<nsIDOMNode> block1, block2;
if (mEditor->IsBlockNode(selNode)) block1 = selNode;
else block1 = mEditor->GetBlockNodeParent(selNode);
block2 = mEditor->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, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
res = aSelection->Collapse(selNode,selOffset);
if (NS_FAILED(res)) return res;
}
return res;
}
nsresult
@ -291,7 +326,26 @@ nsTextEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
if (mFlags & nsIHTMLEditor::eEditorSingleLineMask) {
*aCancel = PR_TRUE;
}
else {
else
{
*aCancel = PR_FALSE;
// if the selection isn't collapsed, delete it.
PRBool bCollapsed;
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
if (NS_FAILED(res)) return res;
if (!bCollapsed)
{
res = mEditor->DeleteSelection(nsIEditor::eDoNothing);
if (NS_FAILED(res)) return res;
}
res = WillInsert(aSelection, aCancel);
if (NS_FAILED(res)) return res;
// initialize out param
// we want to ignore result of WillInsert()
*aCancel = PR_FALSE;
// Mail rule: split any <pre> tags in the way,
// since they're probably quoted text.
// For now, do this for all plaintext since mail is our main customer
@ -300,7 +354,6 @@ nsTextEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
{
nsCOMPtr<nsIDOMNode> preNode, selNode;
PRInt32 selOffset, newOffset;
nsresult res;
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
@ -317,9 +370,7 @@ nsTextEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
res = aSelection->Collapse(selNode, newOffset);
}
}
}
*aCancel = PR_FALSE;
}
}
return NS_OK;
}
@ -327,7 +378,53 @@ nsTextEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
nsresult
nsTextEditRules::DidInsertBreak(nsIDOMSelection *aSelection, nsresult aResult)
{
return NS_OK;
// if we are at the end of the document, we need to insert
// a special mozBR following the normal br, and then set the
// selection to after the mozBR.
PRInt32 selOffset;
nsCOMPtr<nsIDOMNode> nearNode, selNode;
nsresult res;
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
res = GetPriorHTMLNode(selNode, selOffset, &nearNode);
if (NS_FAILED(res)) return res;
if (nearNode && IsBreak(nearNode) && !IsMozBR(nearNode))
{
PRBool bIsLast;
res = IsLastEditableChild(nearNode, &bIsLast);
if (NS_FAILED(res)) return res;
if (bIsLast)
{
// need to insert special moz BR. Why? Because if we don't
// the user will see no new line for the break. Also, things
// like table cells won't grow in height.
nsCOMPtr<nsIDOMNode> brNode;
res = CreateMozBR(selNode, selOffset, &brNode);
if (NS_FAILED(res)) return res;
res = nsEditor::GetNodeLocation(brNode, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
res = aSelection->Collapse(selNode,selOffset+1);
if (NS_FAILED(res)) return res;
}
else
{
// ok, the br inst the last child. But it might be second-to-last
// with a mozBR already exiting after it. In this case we have to
// move the selection to after the mozBR so it will show up on the
// empty line.
nsCOMPtr<nsIDOMNode> nextNode;
res = GetNextHTMLNode(nearNode, &nextNode);
if (NS_FAILED(res)) return res;
if (IsMozBR(nextNode))
{
res = nsEditor::GetNodeLocation(nextNode, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
res = aSelection->Collapse(selNode,selOffset+1);
if (NS_FAILED(res)) return res;
}
}
}
return res;
}
nsresult
@ -361,6 +458,23 @@ nsTextEditRules::WillInsertText(nsIDOMSelection *aSelection,
if (NS_FAILED(res)) return res;
}
// if the selection isn't collapsed, delete it.
PRBool bCollapsed;
res = aSelection->GetIsCollapsed(&bCollapsed);
if (NS_FAILED(res)) return res;
if (!bCollapsed)
{
res = mEditor->DeleteSelection(nsIEditor::eDoNothing);
if (NS_FAILED(res)) return res;
}
res = WillInsert(aSelection, aCancel);
if (NS_FAILED(res)) return res;
// initialize out param
// we want to ignore result of WillInsert()
*aCancel = PR_FALSE;
// do text insertion
PRBool bCancel;
res = DoTextInsertion(aSelection, &bCancel, aOutString, aTypeInState);
@ -1246,3 +1360,354 @@ nsTextEditRules::DoTextInsertion(nsIDOMSelection *aSelection,
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetPriorHTMLSibling: returns the previous editable sibling, if there is
// one within the parent
//
nsresult
nsTextEditRules::GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = NS_OK;
*outNode = nsnull;
nsCOMPtr<nsIDOMNode> temp, node = do_QueryInterface(inNode);
while (1)
{
res = node->GetPreviousSibling(getter_AddRefs(temp));
if (NS_FAILED(res)) return res;
if (!temp) return NS_ERROR_FAILURE;
// if it's editable, we're done
if (mEditor->IsEditable(temp)) break;
// otherwise try again
node = temp;
}
*outNode = temp;
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetNextHTMLSibling: returns the next editable sibling, if there is
// one within the parent
//
nsresult
nsTextEditRules::GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = NS_OK;
*outNode = nsnull;
nsCOMPtr<nsIDOMNode> temp, node = do_QueryInterface(inNode);
while (1)
{
res = node->GetNextSibling(getter_AddRefs(temp));
if (NS_FAILED(res)) return res;
if (!temp) return NS_ERROR_FAILURE;
// if it's editable, we're done
if (mEditor->IsEditable(temp)) break;
// otherwise try again
node = temp;
}
*outNode = temp;
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetPriorHTMLNode: returns the previous editable leaf node, if there is
// one within the <body>
//
nsresult
nsTextEditRules::GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->GetPriorNode(inNode, PR_TRUE, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// if it's not in the body, then zero it out
if (*outNode && !InBody(*outNode))
{
*outNode = nsnull;
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetPriorHTMLNode: same as above but takes {parent,offset} instead of node
//
nsresult
nsTextEditRules::GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->GetPriorNode(inParent, inOffset, PR_TRUE, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// if it's not in the body, then zero it out
if (*outNode && !InBody(*outNode))
{
*outNode = nsnull;
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetNextHTMLNode: returns the previous editable leaf node, if there is
// one within the <body>
//
nsresult
nsTextEditRules::GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->GetNextNode(inNode, PR_TRUE, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// if it's not in the body, then zero it out
if (*outNode && !InBody(*outNode))
{
*outNode = nsnull;
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetNHTMLextNode: same as above but takes {parent,offset} instead of node
//
nsresult
nsTextEditRules::GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
{
if (!outNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->GetNextNode(inParent, inOffset, PR_TRUE, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// if it's not in the body, then zero it out
if (*outNode && !InBody(*outNode))
{
*outNode = nsnull;
}
return res;
}
nsresult
nsTextEditRules::IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst)
{
// check parms
if (!aOutIsFirst || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutIsFirst = PR_FALSE;
// find first editable child and compare it to aNode
nsCOMPtr<nsIDOMNode> parent, firstChild;
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
if (!parent) return NS_ERROR_FAILURE;
res = GetFirstEditableChild(parent, &firstChild);
if (NS_FAILED(res)) return res;
*aOutIsFirst = (firstChild.get() == aNode);
return res;
}
nsresult
nsTextEditRules::IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast)
{
// check parms
if (!aOutIsLast || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutIsLast = PR_FALSE;
// find last editable child and compare it to aNode
nsCOMPtr<nsIDOMNode> parent, lastChild;
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
if (!parent) return NS_ERROR_FAILURE;
res = GetLastEditableChild(parent, &lastChild);
if (NS_FAILED(res)) return res;
*aOutIsLast = (lastChild.get() == aNode);
return res;
}
nsresult
nsTextEditRules::GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild)
{
// check parms
if (!aOutFirstChild || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutFirstChild = nsnull;
// find first editable child
nsCOMPtr<nsIDOMNode> child;
nsresult res = aNode->GetFirstChild(getter_AddRefs(child));
if (NS_FAILED(res)) return res;
while (child && !mEditor->IsEditable(child))
{
nsCOMPtr<nsIDOMNode> tmp;
res = child->GetNextSibling(getter_AddRefs(tmp));
if (NS_FAILED(res)) return res;
if (!tmp) return NS_ERROR_FAILURE;
child = tmp;
}
*aOutFirstChild = child;
return res;
}
nsresult
nsTextEditRules::GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild)
{
// check parms
if (!aOutLastChild || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutLastChild = nsnull;
// find last editable child
nsCOMPtr<nsIDOMNode> child;
nsresult res = aNode->GetLastChild(getter_AddRefs(child));
if (NS_FAILED(res)) return res;
while (child && !mEditor->IsEditable(child))
{
nsCOMPtr<nsIDOMNode> tmp;
res = child->GetPreviousSibling(getter_AddRefs(tmp));
if (NS_FAILED(res)) return res;
if (!tmp) return NS_ERROR_FAILURE;
child = tmp;
}
*aOutLastChild = child;
return res;
}
///////////////////////////////////////////////////////////////////////////
// IsBody: true if node an html body node
//
PRBool
nsTextEditRules::IsBody(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null node passed to nsTextEditRules::IsBody");
nsAutoString tag;
nsEditor::GetTagString(node,tag);
tag.ToLowerCase();
if (tag == "body")
{
return PR_TRUE;
}
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsBreak: true if node an html break node
//
PRBool
nsTextEditRules::IsBreak(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null node passed to nsTextEditRules::IsBreak");
nsAutoString tag;
nsEditor::GetTagString(node,tag);
tag.ToLowerCase();
if (tag == "br")
{
return PR_TRUE;
}
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsMozBR: true if node an html br node with type = _moz
//
PRBool
nsTextEditRules::IsMozBR(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null node passed to nsTextEditRules::IsMozBR");
if (IsBreak(node) && HasMozAttr(node)) return PR_TRUE;
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// HasMozAttr: true if node has type attribute = _moz
// (used to indicate the div's and br's we use in
// mail compose rules)
//
PRBool
nsTextEditRules::HasMozAttr(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null parent passed to nsTextEditRules::HasMozAttr");
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(node);
if (elem)
{
nsAutoString typeAttrName("type");
nsAutoString typeAttrVal;
nsresult res = elem->GetAttribute(typeAttrName, typeAttrVal);
typeAttrVal.ToLowerCase();
if (NS_SUCCEEDED(res) && (typeAttrVal == "_moz"))
return PR_TRUE;
}
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// InBody: true if node is a descendant of the body
//
PRBool
nsTextEditRules::InBody(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null parent passed to nsTextEditRules::InBody");
nsCOMPtr<nsIDOMNode> tmp;
nsCOMPtr<nsIDOMNode> p = do_QueryInterface(node);
while (p && !IsBody(p))
{
if ( NS_FAILED(p->GetParentNode(getter_AddRefs(tmp))) || !tmp) // no parent, ran off top of tree
return PR_FALSE;
p = tmp;
}
if (p) return PR_TRUE;
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// CreateMozBR: put a BR node with moz attribute at {aNode, aOffset}
//
nsresult
nsTextEditRules::CreateMozBR(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outBRNode)
{
if (!inParent || !outBRNode) return NS_ERROR_NULL_POINTER;
nsresult res = mEditor->CreateBR(inParent, inOffset, outBRNode);
if (NS_FAILED(res)) return res;
// give it special moz attr
nsCOMPtr<nsIDOMElement> brElem = do_QueryInterface(*outBRNode);
if (brElem)
{
res = mEditor->SetAttribute(brElem, "type", "_moz");
if (NS_FAILED(res)) return res;
}
return res;
}

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

@ -200,6 +200,28 @@ protected:
const nsString *aInString,
TypeInState aTypeInState);
nsresult GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
nsresult IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst);
nsresult IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast);
nsresult GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild);
nsresult GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild);
static PRBool IsBody(nsIDOMNode *aNode);
static PRBool IsBreak(nsIDOMNode *aNode);
static PRBool IsMozBR(nsIDOMNode *aNode);
static PRBool HasMozAttr(nsIDOMNode *aNode);
static PRBool InBody(nsIDOMNode *aNode);
nsresult CreateMozBR(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outBRNode);
// data
nsHTMLEditor *mEditor; // note that we do not refcount the editor
nsString mPasswordText; // a buffer we use to store the real value of password editors