added in some rules code for mail quoting. This

This commit is contained in:
jfrancis%netscape.com 2000-01-10 10:13:58 +00:00
Родитель 8a0147917f
Коммит e72a2924a8
14 изменённых файлов: 770 добавлений и 576 удалений

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

@ -148,6 +148,7 @@ nsEditor::nsEditor()
, mTxnStartNode(nsnull)
, mTxnStartOffset(0)
, mShouldTxnSetSelection(PR_TRUE)
, mBodyElement(nsnull)
, mInIMEMode(PR_FALSE)
, mIMETextRangeList(nsnull)
, mIMETextNode(nsnull)
@ -1556,13 +1557,21 @@ nsEditor::ForceCompositionEnd()
NS_IMETHODIMP
nsEditor::GetBodyElement(nsIDOMElement **aBodyElement)
{
nsresult result;
nsresult result = NS_OK;
if (!aBodyElement)
return NS_ERROR_NULL_POINTER;
*aBodyElement = 0;
if (mBodyElement)
{
// if we have cached the body element, use that
*aBodyElement = mBodyElement;
NS_ADDREF(*aBodyElement);
return result;
}
NS_PRECONDITION(mDocWeak, "bad state, null mDocWeak");
if (!mDocWeak)
return NS_ERROR_NOT_INITIALIZED;
@ -1596,6 +1605,7 @@ nsEditor::GetBodyElement(nsIDOMElement **aBodyElement)
nsCOMPtr<nsIDOMElement> bodyElement = do_QueryInterface(node);
if (bodyElement)
{
mBodyElement = do_QueryInterface(bodyElement);
*aBodyElement = bodyElement;
// A "getter" method should always addref
NS_ADDREF(*aBodyElement);

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

@ -649,6 +649,7 @@ protected:
nsCOMPtr<nsIDOMNode> mTxnStartNode; // saved selection info to pass to placeholder at init time
PRInt32 mTxnStartOffset; // " " " "
PRBool mShouldTxnSetSelection; // turn off for conservative selection adjustment by txns
nsCOMPtr<nsIDOMElement> mBodyElement; // cached body node
//
// data necessary to build IME transactions
//

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

@ -128,6 +128,12 @@ nsHTMLEditRules::BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection)
if (!mActionNesting)
{
mDocChangeRange = nsnull; // clear out our accounting of what changed
// turn off caret
nsCOMPtr<nsIPresShell> pres;
mEditor->GetPresShell(getter_AddRefs(pres));
if (pres) pres->SetCaretEnabled(PR_FALSE);
// check that selection is in subtree defined by body node
ConfirmSelectionInBody();
}
mActionNesting++;
return NS_OK;
@ -145,6 +151,7 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
nsresult res = NS_OK;
if (!--mActionNesting)
{
ConfirmSelectionInBody();
if (action == nsEditor::kOpIgnore) return NS_OK;
nsCOMPtr<nsIDOMSelection>selection;
@ -180,7 +187,13 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
if (NS_FAILED(res)) return res;
// detect empty doc
res = CreateBogusNodeIfNeeded(selection);
// turn on caret
nsCOMPtr<nsIPresShell> pres;
mEditor->GetPresShell(getter_AddRefs(pres));
if (pres) pres->SetCaretEnabled(PR_TRUE);
}
return res;
}
@ -306,6 +319,11 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
// dont put text in places that cant have it
nsAutoString textTag = "__moz_text";
if (!mEditor->IsTextNode(selNode) && !mEditor->CanContainTag(selNode, textTag))
return NS_ERROR_FAILURE;
// split any mailcites in the way
if (mFlags & nsIHTMLEditor::eEditorMailMask)
{
@ -362,44 +380,17 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
if (NS_FAILED(res)) return res;
}
}
/* // if we are right after a moz br, delete it and make a new moz div
PRBool needMozDiv = PR_FALSE;
if (priorNode && IsBreak(priorNode) && HasMozAttr(priorNode)
&& (blockParent == mEditor->GetBlockNodeParent(priorNode)))
{
res = mEditor->DeleteNode(priorNode);
if (NS_FAILED(res)) return res;
// but we only need to make a moz div if we weren't in a listitem
if (!IsListItem(blockParent))
needMozDiv = PR_TRUE;
}
// if we are directly in a body or (non-moz) div, create a moz-div.
// Also creat one if we detected a prior moz br (see above).
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
if (needMozDiv || IsBody(selNode) || IsNormalDiv(selNode))
{
// wrap things up in a moz-div
nsCOMPtr<nsIDOMNode> mozDiv;
res = CreateMozDiv(selNode, selOffset, &mozDiv);
if (NS_FAILED(res)) return res;
// put selection in it
res = aSelection->Collapse(mozDiv, 0);
if (NS_FAILED(res)) return res;
}
*/}
}
char nbspStr[2] = {nbsp, 0};
PRBool bCancel;
nsString theString(*inString); // copy instring for now
if(aAction == kInsertTextIME)
{
// special case for IME. We need this to :
// a) handle null strings, which are meaningful for IME
// b) prevent the string from being broken into substrings,
// which can happen in non-IME processing below.
// special case for IME. We need this to :
// a) handle null strings, which are meaningful for IME
// b) prevent the string from being broken into substrings,
// which can happen in non-IME processing below.
// I should probably convert runs of spaces and tabs here as well
res = DoTextInsertion(aSelection, &bCancel, &theString, typeInState);
}
@ -421,6 +412,7 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
if (NS_FAILED(res)) return res;
res = DoTextInsertion(aSelection, &bCancel, outString, typeInState);
}
#if 0
// is it a solo space?
else if (partialString == " ")
{
@ -435,6 +427,7 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
if (NS_FAILED(res)) return res;
res = DoTextInsertion(aSelection, &bCancel, outString, typeInState);
}
#endif
// is it a solo return?
else if (partialString == "\n")
{
@ -528,41 +521,6 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
if (!blockParent) return NS_ERROR_FAILURE;
/* // break action depends on type of block
PRBool bIsMozDiv = IsMozDiv(blockParent);
PRBool bIsNormalDiv = IsNormalDiv(blockParent);
// body or normal div: insert a normal br
if (IsBody(blockParent) || bIsNormalDiv)
{
nsCOMPtr<nsIDOMNode> brNode;
res = mEditor->InsertBR(&brNode);
if (NS_FAILED(res)) return res;
*aHandled = PR_TRUE;
}
else if (bIsMozDiv)
{
// split it
PRInt32 newOffset;
res = mEditor->SplitNodeDeep( blockParent, node, offset, &newOffset);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMNode> parent;
blockParent->GetParentNode(getter_AddRefs(parent));
nsCOMPtr <nsIDOMNode> rightDiv = nsEditor::GetChildAt(parent, newOffset);
if (!rightDiv || !IsMozDiv(rightDiv)) return NS_ERROR_FAILURE;
// put the trailer br at the end of the lefthand mozdiv
nsCOMPtr <nsIDOMNode> leftDiv;
res = GetPriorHTMLSibling(rightDiv, &leftDiv);
if (NS_FAILED(res)) return res;
if (!leftDiv || !IsMozDiv(leftDiv)) return NS_ERROR_FAILURE;
res = AddTrailerBR(leftDiv);
if (NS_FAILED(res)) return res;
// put selection at beginning of righthand mozdiv
res = aSelection->Collapse(rightDiv, 0);
if (NS_FAILED(res)) return res;
*aHandled = PR_TRUE;
}
*/
// headers: close (or split) header
else if (IsHeader(blockParent))
{
@ -677,14 +635,14 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
if (mEditor->NodesSameType(node, priorNode))
{
// if so, join them!
nsCOMPtr<nsIDOMNode> topParent;
priorNode->GetParentNode(getter_AddRefs(topParent));
*aHandled = PR_TRUE;
res = JoinNodesSmart(priorNode,node,&selNode,&selOffset);
if (NS_FAILED(res)) return res;
// fix up selection
res = aSelection->Collapse(selNode,selOffset);
return res;
nsCOMPtr<nsIDOMNode> topParent;
priorNode->GetParentNode(getter_AddRefs(topParent));
*aHandled = PR_TRUE;
res = JoinNodesSmart(priorNode,node,&selNode,&selOffset);
if (NS_FAILED(res)) return res;
// fix up selection
res = aSelection->Collapse(selNode,selOffset);
return res;
}
}
}
@ -775,14 +733,14 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
if (mEditor->NodesSameType(node, nextNode))
{
// if so, join them!
nsCOMPtr<nsIDOMNode> topParent;
nextNode->GetParentNode(getter_AddRefs(topParent));
*aHandled = PR_TRUE;
res = JoinNodesSmart(nextNode,node,&selNode,&selOffset);
if (NS_FAILED(res)) return res;
// fix up selection
res = aSelection->Collapse(selNode,selOffset);
return res;
nsCOMPtr<nsIDOMNode> topParent;
nextNode->GetParentNode(getter_AddRefs(topParent));
*aHandled = PR_TRUE;
res = JoinNodesSmart(nextNode,node,&selNode,&selOffset);
if (NS_FAILED(res)) return res;
// fix up selection
res = aSelection->Collapse(selNode,selOffset);
return res;
}
}
}
@ -881,18 +839,18 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
res = GetPriorHTMLNode(nodeToDelete, &brNode);
if (IsBreak(brNode))
{
// is brNode also a descendant of same block?
nsCOMPtr<nsIDOMNode> block, brBlock;
block = mEditor->GetBlockNodeParent(nodeToDelete);
brBlock = mEditor->GetBlockNodeParent(brNode);
if (block == brBlock)
{
// delete both breaks
res = mEditor->DeleteNode(brNode);
if (NS_FAILED(res)) return res;
res = mEditor->DeleteNode(nodeToDelete);
// is brNode also a descendant of same block?
nsCOMPtr<nsIDOMNode> block, brBlock;
block = mEditor->GetBlockNodeParent(nodeToDelete);
brBlock = mEditor->GetBlockNodeParent(brNode);
if (block == brBlock)
{
// delete both breaks
res = mEditor->DeleteNode(brNode);
if (NS_FAILED(res)) return res;
res = mEditor->DeleteNode(nodeToDelete);
*aHandled = PR_TRUE;
return res;
return res;
}
// else fall through
}
@ -901,8 +859,8 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
// adjust selection to be right after it
res = aSelection->Collapse(node, offset+1);
if (NS_FAILED(res)) return res;
res = mEditor->DeleteNode(nodeToDelete);
*aHandled = PR_TRUE;
res = mEditor->DeleteNode(nodeToDelete);
*aHandled = PR_TRUE;
return res;
}
}
@ -2951,13 +2909,13 @@ nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection,
//
nsresult
nsHTMLEditRules::ReturnInParagraph(nsIDOMSelection *aSelection,
nsIDOMNode *aHeader,
nsIDOMNode *aPara,
nsIDOMNode *aNode,
PRInt32 aOffset,
PRBool *aCancel,
PRBool *aHandled)
{
if (!aSelection || !aHeader || !aNode || !aCancel || !aHandled)
if (!aSelection || !aPara || !aNode || !aCancel || !aHandled)
{ return NS_ERROR_NULL_POINTER; }
*aCancel = PR_FALSE;
*aHandled = PR_FALSE;
@ -2984,18 +2942,18 @@ nsHTMLEditRules::ReturnInParagraph(nsIDOMSelection *aSelection,
// just fall out to default of inserting a BR
return res;
}
if (IsBreak(sibling))
if (IsBreak(sibling) && !HasMozAttr(sibling))
{
PRInt32 newOffset;
*aCancel = PR_TRUE;
// split the paragraph
res = mEditor->SplitNodeDeep( aPara, aNode, aOffset, &newOffset);
if (NS_FAILED(res)) return res;
// get rid of the break
res = mEditor->DeleteNode(sibling);
if (NS_FAILED(res)) return res;
// split the paragraph
res = mEditor->SplitNodeDeep( aHeader, aNode, aOffset, &newOffset);
if (NS_FAILED(res)) return res;
// position selection inside textnode
res = aSelection->Collapse(aNode,0);
// position selection inside right hand para
res = aSelection->Collapse(aPara,0);
}
// else just fall out to default of inserting a BR
return res;
@ -3011,18 +2969,18 @@ nsHTMLEditRules::ReturnInParagraph(nsIDOMSelection *aSelection,
// just fall out to default of inserting a BR
return res;
}
if (IsBreak(sibling))
if (IsBreak(sibling) && !HasMozAttr(sibling))
{
PRInt32 newOffset;
*aCancel = PR_TRUE;
// split the paragraph
res = mEditor->SplitNodeDeep(aPara, aNode, aOffset, &newOffset);
if (NS_FAILED(res)) return res;
// get rid of the break
res = mEditor->DeleteNode(sibling);
if (NS_FAILED(res)) return res;
// split the paragraph
res = mEditor->SplitNodeDeep( aHeader, aNode, aOffset, &newOffset);
if (NS_FAILED(res)) return res;
// position selection inside textnode
res = aSelection->Collapse(aNode,0);
// position selection inside right hand para
res = aSelection->Collapse(aPara,0);
}
// else just fall out to default of inserting a BR
return res;
@ -3031,9 +2989,36 @@ nsHTMLEditRules::ReturnInParagraph(nsIDOMSelection *aSelection,
// just fall out to default of inserting a BR
return res;
}
// not in a text node. are we next to BR's?
// moose XXX
else
{
// not in a text node.
// is there a BR prior to it?
nsCOMPtr<nsIDOMNode> nearNode;
res = GetPriorHTMLNode(aNode, aOffset, &nearNode);
if (NS_FAILED(res)) return res;
if (!nearNode || !IsBreak(nearNode) || HasMozAttr(nearNode))
{
// is there a BR after to it?
res = GetNextHTMLNode(aNode, aOffset, &nearNode);
if (NS_FAILED(res)) return res;
if (!nearNode || !IsBreak(nearNode) || HasMozAttr(nearNode))
{
// just fall out to default of inserting a BR
return res;
}
}
// else remove sibling br and split para
PRInt32 newOffset;
*aCancel = PR_TRUE;
// split the paragraph
res = mEditor->SplitNodeDeep( aPara, aNode, aOffset, &newOffset);
if (NS_FAILED(res)) return res;
// get rid of the break
res = mEditor->DeleteNode(nearNode);
if (NS_FAILED(res)) return res;
// selection to beginning of right hand para
aSelection->Collapse(aPara,0);
}
return res;
}
@ -3103,18 +3088,18 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,
// if we fail, then that means we need toinsert a break
res = AdjustSelection(aSelection, nsIEditor::eNext);
if (NS_FAILED(res)) return res;
// get the selection location
nsCOMPtr<nsIDOMNode> selNode;
PRInt32 selOffset;
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
// get the selection location
nsCOMPtr<nsIDOMNode> selNode;
PRInt32 selOffset;
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
// are we in a text node?
nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(selNode);
if (!textNode)
{
// time to insert a break
nsCOMPtr<nsIDOMNode> brNode;
// are we in a text node?
nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(selNode);
if (!textNode)
{
// time to insert a break
nsCOMPtr<nsIDOMNode> brNode;
res = CreateMozBR(selNode, selOffset, &brNode);
if (NS_FAILED(res)) return res;
res = nsEditor::GetNodeLocation(brNode, &selNode, &selOffset);
@ -3131,18 +3116,6 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,
res = mEditor->SplitNodeDeep( aListItem, aNode, aOffset, &newOffset);
if (NS_FAILED(res)) return res;
res = aSelection->Collapse(aListItem,0);
#if 0
// insert a moz-br if new list item is empty
PRBool isEmptyNode;
nsCOMPtr<nsIDOMNode> brNode;
res = IsEmptyNode( aListItem, &isEmptyNode);
if (NS_FAILED(res)) return res;
if (isEmptyNode)
{
res = CreateMozBR(aListItem, 0, &brNode);
if (NS_FAILED(res)) return res;
}
#endif
return res;
}
@ -3666,7 +3639,7 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
if (!aSelection) return NS_ERROR_NULL_POINTER;
// if the selection isn't collapsed, do nothing.
// moose: one thing to do instead ischeck for the case of
// moose: one thing to do instead is check for the case of
// only a single break selected, and collapse it. Good thing? Beats me.
PRBool bCollapsed;
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
@ -3674,14 +3647,26 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
if (!bCollapsed) return res;
// get the (collapsed) selection location
nsCOMPtr<nsIDOMNode> selNode;
nsCOMPtr<nsIDOMNode> selNode, temp;
PRInt32 selOffset;
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
temp = selNode;
// are we in an editable node?
while (!mEditor->IsEditable(selNode))
{
// scan up the tree until we find an editable place to be
res = nsEditor::GetNodeLocation(temp, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
if (!selNode) return NS_ERROR_FAILURE;
temp = selNode;
}
// are we in a text node?
nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(selNode);
if (textNode) return NS_OK; // we LIKE it when we are in a text node. that RULZ
if (textNode)
return NS_OK; // we LIKE it when we are in a text node. that RULZ
// do we need to insert a special mozBR? We do if we are:
// 1) in a collapsed selection AND
@ -3698,11 +3683,11 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
if (NS_FAILED(res)) return res;
if (bIsLast)
{
// is nearNode also a descendant of same block?
nsCOMPtr<nsIDOMNode> block, nearBlock;
if (mEditor->IsBlockNode(selNode)) block = selNode;
else block = mEditor->GetBlockNodeParent(selNode);
nearBlock = mEditor->GetBlockNodeParent(nearNode);
// is nearNode also a descendant of same block?
nsCOMPtr<nsIDOMNode> block, nearBlock;
if (mEditor->IsBlockNode(selNode)) block = selNode;
else block = mEditor->GetBlockNodeParent(selNode);
nearBlock = mEditor->GetBlockNodeParent(nearNode);
if (block == nearBlock)
{
// need to insert special moz BR. Why? Because if we don't
@ -3711,10 +3696,10 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
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;
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
@ -3723,16 +3708,37 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
// 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;
}
nsCOMPtr<nsIDOMNode> nextNode;
res = GetNextHTMLNode(nearNode, &nextNode);
if (NS_FAILED(res)) return res;
if (nextNode && 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;
}
else
{
// alright, not that either. But there's one more squirrel to feed:
// the br might be right in front of a new block (ie,:
// <body> text<br> <ol><li>list item</li></ol></body> )
// in this case we also need moz-br.
res = GetNextHTMLSibling(nearNode, &nextNode);
if (NS_FAILED(res)) return res;
if (nextNode && mEditor->IsBlockNode(nextNode))
{
// need to insert special moz BR. Why? Because if we don't
// the user will see no new line for the break.
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;
}
}
}
}
@ -3755,6 +3761,7 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
dir = aAction;
}
// is the nearnode a text node?
if (!nearNode) return NS_OK; // couldn't find a near text node
textNode = do_QueryInterface(nearNode);
if (!textNode) return NS_ERROR_UNEXPECTED;
PRInt32 offset = 0;
@ -3931,21 +3938,21 @@ nsHTMLEditRules::DoTextNodeWhitespace(nsIDOMCharacterData *aTextNode, PRInt32 aS
if (runStr != newStr)
{
// delete the original whitespace run
EditTxn *txn;
EditTxn *txn;
// note 1: we are not telling edit listeners about these because they don't care
// note 2: we are not wrapping these in a placeholder because we know they already are
res = mEditor->CreateTxnForDeleteText(aTextNode, aStart+runStart, runEnd-runStart, (DeleteTextTxn**)&txn);
if (NS_FAILED(res)) return res;
if (!txn) return NS_ERROR_OUT_OF_MEMORY;
if (!txn) return NS_ERROR_OUT_OF_MEMORY;
res = mEditor->Do(txn);
if (NS_FAILED(res)) return res;
// The transaction system (if any) has taken ownwership of txn
NS_IF_RELEASE(txn);
// insert the new run
res = mEditor->CreateTxnForInsertText(newStr, aTextNode, aStart+runStart, (InsertTextTxn**)&txn);
res = mEditor->CreateTxnForInsertText(newStr, aTextNode, aStart+runStart, (InsertTextTxn**)&txn);
if (NS_FAILED(res)) return res;
if (!txn) return NS_ERROR_OUT_OF_MEMORY;
if (!txn) return NS_ERROR_OUT_OF_MEMORY;
res = mEditor->Do(txn);
// The transaction system (if any) has taken ownwership of txns.
NS_IF_RELEASE(txn);
@ -4078,36 +4085,68 @@ nsHTMLEditRules::PopListItem(nsIDOMNode *aListItem, PRBool *aOutOfList)
}
// not needed for now - leaving around in case we go back to it
#if 0
nsresult
nsHTMLEditRules::AddTrailerBR(nsIDOMNode *aNode)
nsHTMLEditRules::ConfirmSelectionInBody()
{
// check parms
if (!aNode) return NS_ERROR_NULL_POINTER;
nsresult res = NS_OK;
// comfirm that this node is a type that we add trailer br's to:
// td, th, li
if (IsListItem(aNode)) // add more types later
nsCOMPtr<nsIDOMElement> bodyElement;
nsCOMPtr<nsIDOMNode> bodyNode;
// get the body
res = mEditor->GetBodyElement(getter_AddRefs(bodyElement));
if (NS_FAILED(res)) return res;
if (!bodyElement) return NS_ERROR_UNEXPECTED;
bodyNode = do_QueryInterface(bodyElement);
// get the selection
nsCOMPtr<nsIDOMSelection>selection;
res = mEditor->GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
// get the selection start location
nsCOMPtr<nsIDOMNode> selNode, temp, parent;
PRInt32 selOffset;
res = mEditor->GetStartNodeAndOffset(selection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
temp = selNode;
// check that selNode is inside body
while (temp && !IsBody(temp))
{
PRUint32 count;
nsCOMPtr<nsIDOMNode> brNode;
res = mEditor->GetLengthOfDOMNode(aNode, count);
if (NS_FAILED(res)) return res;
res = mEditor->CreateBR(aNode, count, &brNode);
if (NS_FAILED(res)) return res;
// give it special trailer attr
nsCOMPtr<nsIDOMElement> brElem = do_QueryInterface(brNode);
res = mEditor->SetAttribute(brElem, "type", "_moz_trailer");
res = temp->GetParentNode(getter_AddRefs(parent));
temp = parent;
}
else
// if we aren't in the body, force the issue
if (!temp)
{
NS_NOTREACHED("editor error: nsHTMLEditRules::AddTrailerBR() called on bad node type");
// uncomment this to see when we get bad selections
// NS_NOTREACHED("selection not in body");
selection->Collapse(bodyNode,0);
}
return res;
// get the selection end location
res = mEditor->GetEndNodeAndOffset(selection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
temp = selNode;
// check that selNode is inside body
while (temp && !IsBody(temp))
{
res = temp->GetParentNode(getter_AddRefs(parent));
temp = parent;
}
// if we aren't in the body, force the issue
if (!temp)
{
// uncomment this to see when we get bad selections
// NS_NOTREACHED("selection not in body");
selection->Collapse(bodyNode,0);
}
}
#endif
nsresult
nsHTMLEditRules::UpdateDocChangeRange(nsIDOMRange *aRange)

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

@ -156,6 +156,7 @@ protected:
nsresult UpdateDocChangeRange(nsIDOMRange *aRange);
nsresult ConvertWhitespace(const nsString & inString, nsString & outString);
nsresult ConfirmSelectionInBody();
// removed from use:
#if 0

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

@ -3639,43 +3639,48 @@ NS_IMETHODIMP nsHTMLEditor::PasteAsQuotation()
NS_IMETHODIMP nsHTMLEditor::PasteAsCitedQuotation(const nsString& aCitation)
{
nsAutoEditBatch beginBatching(this);
nsCOMPtr<nsIDOMNode> newNode;
nsAutoString tag("blockquote");
nsresult res = DeleteSelectionAndCreateNode(tag, getter_AddRefs(newNode));
if (NS_FAILED(res)) return res;
if (!newNode) return NS_ERROR_NULL_POINTER;
// Try to set type=cite. Ignore it if this fails.
nsCOMPtr<nsIDOMElement> newElement (do_QueryInterface(newNode));
if (newElement)
{
nsAutoString type ("type");
nsAutoString cite ("cite");
newElement->SetAttribute(type, cite);
}
// Set the selection to the underneath the node we just inserted:
// get selection
nsCOMPtr<nsIDOMSelection> selection;
res = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res) || !selection)
{
#ifdef DEBUG_akkana
printf("Can't get selection!");
#endif
}
nsresult res = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
if (!selection) return NS_ERROR_NULL_POINTER;
res = selection->Collapse(newNode, 0);
if (NS_FAILED(res))
// 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)
{
#ifdef DEBUG_akkana
printf("Couldn't collapse");
#endif
// XXX: error result: should res be returned here?
}
nsCOMPtr<nsIDOMNode> newNode;
nsAutoString tag("blockquote");
res = DeleteSelectionAndCreateNode(tag, getter_AddRefs(newNode));
if (NS_FAILED(res)) return res;
if (!newNode) return NS_ERROR_NULL_POINTER;
res = Paste();
// Try to set type=cite. Ignore it if this fails.
nsCOMPtr<nsIDOMElement> newElement (do_QueryInterface(newNode));
if (newElement)
{
nsAutoString type ("type");
nsAutoString cite ("cite");
newElement->SetAttribute(type, cite);
}
// Set the selection to the underneath the node we just inserted:
res = selection->Collapse(newNode, 0);
if (NS_FAILED(res))
{
#ifdef DEBUG_akkana
printf("Couldn't collapse");
#endif
// XXX: error result: should res be returned here?
}
res = Paste();
}
return res;
}
@ -3800,42 +3805,53 @@ nsHTMLEditor::InsertAsPlaintextQuotation(const nsString& aQuotedText,
nsAutoEditBatch beginBatching(this);
// Wrap the inserted quote in a <pre> so it won't be wrapped:
nsCOMPtr<nsIDOMNode> preNode;
nsAutoString tag("pre");
rv = DeleteSelectionAndCreateNode(tag, getter_AddRefs(preNode));
// If this succeeded, then set selection inside the pre
// so the inserted text will end up there.
// If it failed, we don't care what the return value was,
// but we'll fall through and try to insert the text anyway.
// get selection
nsCOMPtr<nsIDOMSelection> selection;
rv = GetSelection(getter_AddRefs(selection));
if (NS_SUCCEEDED(rv) && preNode)
{
if (NS_SUCCEEDED(rv) && selection)
selection->Collapse(preNode, 0);
}
if (NS_FAILED(rv)) return rv;
if (!selection) return NS_ERROR_NULL_POINTER;
rv = InsertText(quotedStuff);
if (aNodeInserted)
// give rules a chance to handle or cancel
nsTextRulesInfo ruleInfo(nsHTMLEditRules::kInsertElement);
PRBool cancel, handled;
rv = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
if (NS_FAILED(rv)) return rv;
if (cancel) return NS_OK; // rules canceled the operation
if (!handled)
{
if (NS_SUCCEEDED(rv))
// Wrap the inserted quote in a <pre> so it won't be wrapped:
nsCOMPtr<nsIDOMNode> preNode;
nsAutoString tag("pre");
rv = DeleteSelectionAndCreateNode(tag, getter_AddRefs(preNode));
// If this succeeded, then set selection inside the pre
// so the inserted text will end up there.
// If it failed, we don't care what the return value was,
// but we'll fall through and try to insert the text anyway.
if (NS_SUCCEEDED(rv) && preNode)
{
*aNodeInserted = preNode;
NS_IF_ADDREF(*aNodeInserted);
selection->Collapse(preNode, 0);
}
rv = InsertText(quotedStuff);
if (aNodeInserted)
{
if (NS_SUCCEEDED(rv))
{
*aNodeInserted = preNode;
NS_IF_ADDREF(*aNodeInserted);
}
}
// Set the selection to just after the inserted node:
if (NS_SUCCEEDED(rv) && preNode)
{
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
if (NS_SUCCEEDED(GetNodeLocation(preNode, &parent, &offset)) && parent)
selection->Collapse(parent, offset+1);
}
}
// Set the selection to just after the inserted node:
if (NS_SUCCEEDED(rv) && preNode)
{
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
if (NS_SUCCEEDED(GetNodeLocation(preNode, &parent, &offset)) && parent)
selection->Collapse(parent, offset+1);
}
return rv;
}
@ -3848,48 +3864,61 @@ nsHTMLEditor::InsertAsCitedQuotation(const nsString& aQuotedText,
nsAutoEditBatch beginBatching(this);
nsCOMPtr<nsIDOMNode> newNode;
nsAutoRules beginRulesSniffing(this, kOpInsertElement, nsIEditor::eNext);
nsAutoString tag("blockquote");
nsresult res = DeleteSelectionAndCreateNode(tag, getter_AddRefs(newNode));
if (NS_FAILED(res)) return res;
if (!newNode) return NS_ERROR_NULL_POINTER;
// Try to set type=cite. Ignore it if this fails.
nsCOMPtr<nsIDOMElement> newElement (do_QueryInterface(newNode));
// get selection
nsCOMPtr<nsIDOMSelection> selection;
res = GetSelection(getter_AddRefs(selection));
if (newElement)
nsresult 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)
{
nsAutoString type ("type");
nsAutoString cite ("cite");
newElement->SetAttribute(type, cite);
nsAutoString tag("blockquote");
res = DeleteSelectionAndCreateNode(tag, getter_AddRefs(newNode));
if (NS_FAILED(res)) return res;
if (!newNode) return NS_ERROR_NULL_POINTER;
if (aCitation.Length() > 0)
newElement->SetAttribute(cite, aCitation);
// Set the selection inside the blockquote so aQuotedText will go there:
if (NS_SUCCEEDED(res) && selection)
selection->Collapse(newNode, 0);
}
res = InsertHTMLWithCharset(aQuotedText, aCharset);
if (aNodeInserted)
{
if (NS_SUCCEEDED(res))
// Try to set type=cite. Ignore it if this fails.
nsCOMPtr<nsIDOMElement> newElement (do_QueryInterface(newNode));
if (newElement)
{
*aNodeInserted = newNode;
NS_IF_ADDREF(*aNodeInserted);
nsAutoString type ("type");
nsAutoString cite ("cite");
newElement->SetAttribute(type, cite);
if (aCitation.Length() > 0)
newElement->SetAttribute(cite, aCitation);
// Set the selection inside the blockquote so aQuotedText will go there:
if (NS_SUCCEEDED(res))
selection->Collapse(newNode, 0);
}
res = InsertHTMLWithCharset(aQuotedText, aCharset);
if (aNodeInserted)
{
if (NS_SUCCEEDED(res))
{
*aNodeInserted = newNode;
NS_IF_ADDREF(*aNodeInserted);
}
}
// Set the selection to just after the inserted node:
if (NS_SUCCEEDED(res) && newNode)
{
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
if (NS_SUCCEEDED(GetNodeLocation(newNode, &parent, &offset)) && parent)
selection->Collapse(parent, offset+1);
}
}
// Set the selection to just after the inserted node:
if (NS_SUCCEEDED(res) && newNode)
{
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
if (NS_SUCCEEDED(GetNodeLocation(newNode, &parent, &offset)) && parent)
selection->Collapse(parent, offset+1);
}
return res;
}
@ -4228,6 +4257,17 @@ nsHTMLEditor::EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
}
PRBool
nsHTMLEditor::CanContainTag(nsIDOMNode* aParent, const nsString &aTag)
{
// CNavDTD gives some unwanted results. We override them here.
// if parent is a list and tag is text, say "no".
if (IsListNode(aParent) && (aTag == "__moz_text"))
return PR_FALSE;
// else fall thru
return nsEditor::CanContainTag(aParent, aTag);
}
#ifdef XP_MAC
#pragma mark -
@ -5266,6 +5306,8 @@ nsHTMLEditor::SetCaretInTableCell(nsIDOMElement* aElement)
node = firstChild;
}
}
# if 0
// I've ifdef'd this out because it isn't finished and I'm not sure what the intent is.
PRInt32 offset = 0;
nsCOMPtr<nsIDOMNode>lastChild;
res = parent->GetLastChild(getter_AddRefs(lastChild));
@ -5291,13 +5333,14 @@ nsHTMLEditor::SetCaretInTableCell(nsIDOMElement* aElement)
// We have > 1 node, so set to end of content
}
}
#endif
// Set selection at beginning of deepest node
// Should we set
nsCOMPtr<nsIDOMSelection> selection;
res = GetSelection(getter_AddRefs(selection));
if (NS_SUCCEEDED(res) && selection)
if (NS_SUCCEEDED(res) && selection && firstChild)
{
res = selection->Collapse(parent, offset);
res = selection->Collapse(firstChild, 0);
if (NS_SUCCEEDED(res))
caretIsSet = PR_TRUE;
}

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

@ -244,6 +244,8 @@ public:
/* ------------ nsICSSLoaderObserver -------------- */
NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet*aSheet, PRBool aNotify);
/* ------------ nsEditor overrides ---------------- */
/** All editor operations which alter the doc should be prefaced
* with a call to StartOperation, naming the action and direction */
NS_IMETHOD StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
@ -252,6 +254,9 @@ public:
* with a call to EndOperation, naming the action and direction */
NS_IMETHOD EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
/** returns PR_TRUE if aParent can contain a child of type aTag */
PRBool CanContainTag(nsIDOMNode* aParent, const nsString &aTag);
/* ------------ Utility Routines, not part of public API -------------- */
NS_IMETHOD GetBodyStyleContext(nsIStyleContext** aStyleContext);

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

@ -299,7 +299,7 @@ nsTextEditRules::WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel)
// get the (collapsed) selection location
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
// get next node
// get prior node
res = GetPriorHTMLNode(selNode, selOffset, &priorNode);
if (NS_SUCCEEDED(res) && priorNode && IsMozBR(priorNode))
{
@ -1014,8 +1014,6 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection,
PRBool isCollapsed;
aSelection->GetIsCollapsed(&isCollapsed);
NS_ASSERTION(PR_TRUE==isCollapsed, "selection not collapsed after delete selection.");
// if the delete selection resulted in no content
// insert a special bogus text node with a &nbsp; character in it.
if (NS_SUCCEEDED(res)) // only do this work if DeleteSelection completed successfully
{
// if we don't have an empty document, check the selection to see if any collapsing is necessary
@ -1047,7 +1045,7 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection,
{
nsCOMPtr<nsIDOMCharacterData>selectedNodeAsText;
selectedNodeAsText = do_QueryInterface(selectedNode);
if (selectedNodeAsText)
if (selectedNodeAsText && mEditor->IsEditable(selectedNode))
{
nsCOMPtr<nsIDOMNode> siblingNode;
selectedNode->GetPreviousSibling(getter_AddRefs(siblingNode));
@ -1055,7 +1053,7 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection,
{
nsCOMPtr<nsIDOMCharacterData>siblingNodeAsText;
siblingNodeAsText = do_QueryInterface(siblingNode);
if (siblingNodeAsText)
if (siblingNodeAsText && mEditor->IsEditable(siblingNode))
{
PRUint32 siblingLength; // the length of siblingNode before the join
siblingNodeAsText->GetLength(&siblingLength);
@ -1072,7 +1070,7 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection,
{
nsCOMPtr<nsIDOMCharacterData>siblingNodeAsText;
siblingNodeAsText = do_QueryInterface(siblingNode);
if (siblingNodeAsText)
if (siblingNodeAsText && mEditor->IsEditable(siblingNode))
{
PRUint32 selectedNodeLength; // the length of siblingNode before the join
selectedNodeAsText->GetLength(&selectedNodeLength);

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

@ -148,6 +148,7 @@ nsEditor::nsEditor()
, mTxnStartNode(nsnull)
, mTxnStartOffset(0)
, mShouldTxnSetSelection(PR_TRUE)
, mBodyElement(nsnull)
, mInIMEMode(PR_FALSE)
, mIMETextRangeList(nsnull)
, mIMETextNode(nsnull)
@ -1556,13 +1557,21 @@ nsEditor::ForceCompositionEnd()
NS_IMETHODIMP
nsEditor::GetBodyElement(nsIDOMElement **aBodyElement)
{
nsresult result;
nsresult result = NS_OK;
if (!aBodyElement)
return NS_ERROR_NULL_POINTER;
*aBodyElement = 0;
if (mBodyElement)
{
// if we have cached the body element, use that
*aBodyElement = mBodyElement;
NS_ADDREF(*aBodyElement);
return result;
}
NS_PRECONDITION(mDocWeak, "bad state, null mDocWeak");
if (!mDocWeak)
return NS_ERROR_NOT_INITIALIZED;
@ -1596,6 +1605,7 @@ nsEditor::GetBodyElement(nsIDOMElement **aBodyElement)
nsCOMPtr<nsIDOMElement> bodyElement = do_QueryInterface(node);
if (bodyElement)
{
mBodyElement = do_QueryInterface(bodyElement);
*aBodyElement = bodyElement;
// A "getter" method should always addref
NS_ADDREF(*aBodyElement);

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

@ -649,6 +649,7 @@ protected:
nsCOMPtr<nsIDOMNode> mTxnStartNode; // saved selection info to pass to placeholder at init time
PRInt32 mTxnStartOffset; // " " " "
PRBool mShouldTxnSetSelection; // turn off for conservative selection adjustment by txns
nsCOMPtr<nsIDOMElement> mBodyElement; // cached body node
//
// data necessary to build IME transactions
//

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

@ -128,6 +128,12 @@ nsHTMLEditRules::BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection)
if (!mActionNesting)
{
mDocChangeRange = nsnull; // clear out our accounting of what changed
// turn off caret
nsCOMPtr<nsIPresShell> pres;
mEditor->GetPresShell(getter_AddRefs(pres));
if (pres) pres->SetCaretEnabled(PR_FALSE);
// check that selection is in subtree defined by body node
ConfirmSelectionInBody();
}
mActionNesting++;
return NS_OK;
@ -145,6 +151,7 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
nsresult res = NS_OK;
if (!--mActionNesting)
{
ConfirmSelectionInBody();
if (action == nsEditor::kOpIgnore) return NS_OK;
nsCOMPtr<nsIDOMSelection>selection;
@ -180,7 +187,13 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
if (NS_FAILED(res)) return res;
// detect empty doc
res = CreateBogusNodeIfNeeded(selection);
// turn on caret
nsCOMPtr<nsIPresShell> pres;
mEditor->GetPresShell(getter_AddRefs(pres));
if (pres) pres->SetCaretEnabled(PR_TRUE);
}
return res;
}
@ -306,6 +319,11 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
// dont put text in places that cant have it
nsAutoString textTag = "__moz_text";
if (!mEditor->IsTextNode(selNode) && !mEditor->CanContainTag(selNode, textTag))
return NS_ERROR_FAILURE;
// split any mailcites in the way
if (mFlags & nsIHTMLEditor::eEditorMailMask)
{
@ -362,44 +380,17 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
if (NS_FAILED(res)) return res;
}
}
/* // if we are right after a moz br, delete it and make a new moz div
PRBool needMozDiv = PR_FALSE;
if (priorNode && IsBreak(priorNode) && HasMozAttr(priorNode)
&& (blockParent == mEditor->GetBlockNodeParent(priorNode)))
{
res = mEditor->DeleteNode(priorNode);
if (NS_FAILED(res)) return res;
// but we only need to make a moz div if we weren't in a listitem
if (!IsListItem(blockParent))
needMozDiv = PR_TRUE;
}
// if we are directly in a body or (non-moz) div, create a moz-div.
// Also creat one if we detected a prior moz br (see above).
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
if (needMozDiv || IsBody(selNode) || IsNormalDiv(selNode))
{
// wrap things up in a moz-div
nsCOMPtr<nsIDOMNode> mozDiv;
res = CreateMozDiv(selNode, selOffset, &mozDiv);
if (NS_FAILED(res)) return res;
// put selection in it
res = aSelection->Collapse(mozDiv, 0);
if (NS_FAILED(res)) return res;
}
*/}
}
char nbspStr[2] = {nbsp, 0};
PRBool bCancel;
nsString theString(*inString); // copy instring for now
if(aAction == kInsertTextIME)
{
// special case for IME. We need this to :
// a) handle null strings, which are meaningful for IME
// b) prevent the string from being broken into substrings,
// which can happen in non-IME processing below.
// special case for IME. We need this to :
// a) handle null strings, which are meaningful for IME
// b) prevent the string from being broken into substrings,
// which can happen in non-IME processing below.
// I should probably convert runs of spaces and tabs here as well
res = DoTextInsertion(aSelection, &bCancel, &theString, typeInState);
}
@ -421,6 +412,7 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
if (NS_FAILED(res)) return res;
res = DoTextInsertion(aSelection, &bCancel, outString, typeInState);
}
#if 0
// is it a solo space?
else if (partialString == " ")
{
@ -435,6 +427,7 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
if (NS_FAILED(res)) return res;
res = DoTextInsertion(aSelection, &bCancel, outString, typeInState);
}
#endif
// is it a solo return?
else if (partialString == "\n")
{
@ -528,41 +521,6 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
if (!blockParent) return NS_ERROR_FAILURE;
/* // break action depends on type of block
PRBool bIsMozDiv = IsMozDiv(blockParent);
PRBool bIsNormalDiv = IsNormalDiv(blockParent);
// body or normal div: insert a normal br
if (IsBody(blockParent) || bIsNormalDiv)
{
nsCOMPtr<nsIDOMNode> brNode;
res = mEditor->InsertBR(&brNode);
if (NS_FAILED(res)) return res;
*aHandled = PR_TRUE;
}
else if (bIsMozDiv)
{
// split it
PRInt32 newOffset;
res = mEditor->SplitNodeDeep( blockParent, node, offset, &newOffset);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMNode> parent;
blockParent->GetParentNode(getter_AddRefs(parent));
nsCOMPtr <nsIDOMNode> rightDiv = nsEditor::GetChildAt(parent, newOffset);
if (!rightDiv || !IsMozDiv(rightDiv)) return NS_ERROR_FAILURE;
// put the trailer br at the end of the lefthand mozdiv
nsCOMPtr <nsIDOMNode> leftDiv;
res = GetPriorHTMLSibling(rightDiv, &leftDiv);
if (NS_FAILED(res)) return res;
if (!leftDiv || !IsMozDiv(leftDiv)) return NS_ERROR_FAILURE;
res = AddTrailerBR(leftDiv);
if (NS_FAILED(res)) return res;
// put selection at beginning of righthand mozdiv
res = aSelection->Collapse(rightDiv, 0);
if (NS_FAILED(res)) return res;
*aHandled = PR_TRUE;
}
*/
// headers: close (or split) header
else if (IsHeader(blockParent))
{
@ -677,14 +635,14 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
if (mEditor->NodesSameType(node, priorNode))
{
// if so, join them!
nsCOMPtr<nsIDOMNode> topParent;
priorNode->GetParentNode(getter_AddRefs(topParent));
*aHandled = PR_TRUE;
res = JoinNodesSmart(priorNode,node,&selNode,&selOffset);
if (NS_FAILED(res)) return res;
// fix up selection
res = aSelection->Collapse(selNode,selOffset);
return res;
nsCOMPtr<nsIDOMNode> topParent;
priorNode->GetParentNode(getter_AddRefs(topParent));
*aHandled = PR_TRUE;
res = JoinNodesSmart(priorNode,node,&selNode,&selOffset);
if (NS_FAILED(res)) return res;
// fix up selection
res = aSelection->Collapse(selNode,selOffset);
return res;
}
}
}
@ -775,14 +733,14 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
if (mEditor->NodesSameType(node, nextNode))
{
// if so, join them!
nsCOMPtr<nsIDOMNode> topParent;
nextNode->GetParentNode(getter_AddRefs(topParent));
*aHandled = PR_TRUE;
res = JoinNodesSmart(nextNode,node,&selNode,&selOffset);
if (NS_FAILED(res)) return res;
// fix up selection
res = aSelection->Collapse(selNode,selOffset);
return res;
nsCOMPtr<nsIDOMNode> topParent;
nextNode->GetParentNode(getter_AddRefs(topParent));
*aHandled = PR_TRUE;
res = JoinNodesSmart(nextNode,node,&selNode,&selOffset);
if (NS_FAILED(res)) return res;
// fix up selection
res = aSelection->Collapse(selNode,selOffset);
return res;
}
}
}
@ -881,18 +839,18 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
res = GetPriorHTMLNode(nodeToDelete, &brNode);
if (IsBreak(brNode))
{
// is brNode also a descendant of same block?
nsCOMPtr<nsIDOMNode> block, brBlock;
block = mEditor->GetBlockNodeParent(nodeToDelete);
brBlock = mEditor->GetBlockNodeParent(brNode);
if (block == brBlock)
{
// delete both breaks
res = mEditor->DeleteNode(brNode);
if (NS_FAILED(res)) return res;
res = mEditor->DeleteNode(nodeToDelete);
// is brNode also a descendant of same block?
nsCOMPtr<nsIDOMNode> block, brBlock;
block = mEditor->GetBlockNodeParent(nodeToDelete);
brBlock = mEditor->GetBlockNodeParent(brNode);
if (block == brBlock)
{
// delete both breaks
res = mEditor->DeleteNode(brNode);
if (NS_FAILED(res)) return res;
res = mEditor->DeleteNode(nodeToDelete);
*aHandled = PR_TRUE;
return res;
return res;
}
// else fall through
}
@ -901,8 +859,8 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
// adjust selection to be right after it
res = aSelection->Collapse(node, offset+1);
if (NS_FAILED(res)) return res;
res = mEditor->DeleteNode(nodeToDelete);
*aHandled = PR_TRUE;
res = mEditor->DeleteNode(nodeToDelete);
*aHandled = PR_TRUE;
return res;
}
}
@ -2951,13 +2909,13 @@ nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection,
//
nsresult
nsHTMLEditRules::ReturnInParagraph(nsIDOMSelection *aSelection,
nsIDOMNode *aHeader,
nsIDOMNode *aPara,
nsIDOMNode *aNode,
PRInt32 aOffset,
PRBool *aCancel,
PRBool *aHandled)
{
if (!aSelection || !aHeader || !aNode || !aCancel || !aHandled)
if (!aSelection || !aPara || !aNode || !aCancel || !aHandled)
{ return NS_ERROR_NULL_POINTER; }
*aCancel = PR_FALSE;
*aHandled = PR_FALSE;
@ -2984,18 +2942,18 @@ nsHTMLEditRules::ReturnInParagraph(nsIDOMSelection *aSelection,
// just fall out to default of inserting a BR
return res;
}
if (IsBreak(sibling))
if (IsBreak(sibling) && !HasMozAttr(sibling))
{
PRInt32 newOffset;
*aCancel = PR_TRUE;
// split the paragraph
res = mEditor->SplitNodeDeep( aPara, aNode, aOffset, &newOffset);
if (NS_FAILED(res)) return res;
// get rid of the break
res = mEditor->DeleteNode(sibling);
if (NS_FAILED(res)) return res;
// split the paragraph
res = mEditor->SplitNodeDeep( aHeader, aNode, aOffset, &newOffset);
if (NS_FAILED(res)) return res;
// position selection inside textnode
res = aSelection->Collapse(aNode,0);
// position selection inside right hand para
res = aSelection->Collapse(aPara,0);
}
// else just fall out to default of inserting a BR
return res;
@ -3011,18 +2969,18 @@ nsHTMLEditRules::ReturnInParagraph(nsIDOMSelection *aSelection,
// just fall out to default of inserting a BR
return res;
}
if (IsBreak(sibling))
if (IsBreak(sibling) && !HasMozAttr(sibling))
{
PRInt32 newOffset;
*aCancel = PR_TRUE;
// split the paragraph
res = mEditor->SplitNodeDeep(aPara, aNode, aOffset, &newOffset);
if (NS_FAILED(res)) return res;
// get rid of the break
res = mEditor->DeleteNode(sibling);
if (NS_FAILED(res)) return res;
// split the paragraph
res = mEditor->SplitNodeDeep( aHeader, aNode, aOffset, &newOffset);
if (NS_FAILED(res)) return res;
// position selection inside textnode
res = aSelection->Collapse(aNode,0);
// position selection inside right hand para
res = aSelection->Collapse(aPara,0);
}
// else just fall out to default of inserting a BR
return res;
@ -3031,9 +2989,36 @@ nsHTMLEditRules::ReturnInParagraph(nsIDOMSelection *aSelection,
// just fall out to default of inserting a BR
return res;
}
// not in a text node. are we next to BR's?
// moose XXX
else
{
// not in a text node.
// is there a BR prior to it?
nsCOMPtr<nsIDOMNode> nearNode;
res = GetPriorHTMLNode(aNode, aOffset, &nearNode);
if (NS_FAILED(res)) return res;
if (!nearNode || !IsBreak(nearNode) || HasMozAttr(nearNode))
{
// is there a BR after to it?
res = GetNextHTMLNode(aNode, aOffset, &nearNode);
if (NS_FAILED(res)) return res;
if (!nearNode || !IsBreak(nearNode) || HasMozAttr(nearNode))
{
// just fall out to default of inserting a BR
return res;
}
}
// else remove sibling br and split para
PRInt32 newOffset;
*aCancel = PR_TRUE;
// split the paragraph
res = mEditor->SplitNodeDeep( aPara, aNode, aOffset, &newOffset);
if (NS_FAILED(res)) return res;
// get rid of the break
res = mEditor->DeleteNode(nearNode);
if (NS_FAILED(res)) return res;
// selection to beginning of right hand para
aSelection->Collapse(aPara,0);
}
return res;
}
@ -3103,18 +3088,18 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,
// if we fail, then that means we need toinsert a break
res = AdjustSelection(aSelection, nsIEditor::eNext);
if (NS_FAILED(res)) return res;
// get the selection location
nsCOMPtr<nsIDOMNode> selNode;
PRInt32 selOffset;
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
// get the selection location
nsCOMPtr<nsIDOMNode> selNode;
PRInt32 selOffset;
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
// are we in a text node?
nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(selNode);
if (!textNode)
{
// time to insert a break
nsCOMPtr<nsIDOMNode> brNode;
// are we in a text node?
nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(selNode);
if (!textNode)
{
// time to insert a break
nsCOMPtr<nsIDOMNode> brNode;
res = CreateMozBR(selNode, selOffset, &brNode);
if (NS_FAILED(res)) return res;
res = nsEditor::GetNodeLocation(brNode, &selNode, &selOffset);
@ -3131,18 +3116,6 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,
res = mEditor->SplitNodeDeep( aListItem, aNode, aOffset, &newOffset);
if (NS_FAILED(res)) return res;
res = aSelection->Collapse(aListItem,0);
#if 0
// insert a moz-br if new list item is empty
PRBool isEmptyNode;
nsCOMPtr<nsIDOMNode> brNode;
res = IsEmptyNode( aListItem, &isEmptyNode);
if (NS_FAILED(res)) return res;
if (isEmptyNode)
{
res = CreateMozBR(aListItem, 0, &brNode);
if (NS_FAILED(res)) return res;
}
#endif
return res;
}
@ -3666,7 +3639,7 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
if (!aSelection) return NS_ERROR_NULL_POINTER;
// if the selection isn't collapsed, do nothing.
// moose: one thing to do instead ischeck for the case of
// moose: one thing to do instead is check for the case of
// only a single break selected, and collapse it. Good thing? Beats me.
PRBool bCollapsed;
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
@ -3674,14 +3647,26 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
if (!bCollapsed) return res;
// get the (collapsed) selection location
nsCOMPtr<nsIDOMNode> selNode;
nsCOMPtr<nsIDOMNode> selNode, temp;
PRInt32 selOffset;
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
temp = selNode;
// are we in an editable node?
while (!mEditor->IsEditable(selNode))
{
// scan up the tree until we find an editable place to be
res = nsEditor::GetNodeLocation(temp, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
if (!selNode) return NS_ERROR_FAILURE;
temp = selNode;
}
// are we in a text node?
nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(selNode);
if (textNode) return NS_OK; // we LIKE it when we are in a text node. that RULZ
if (textNode)
return NS_OK; // we LIKE it when we are in a text node. that RULZ
// do we need to insert a special mozBR? We do if we are:
// 1) in a collapsed selection AND
@ -3698,11 +3683,11 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
if (NS_FAILED(res)) return res;
if (bIsLast)
{
// is nearNode also a descendant of same block?
nsCOMPtr<nsIDOMNode> block, nearBlock;
if (mEditor->IsBlockNode(selNode)) block = selNode;
else block = mEditor->GetBlockNodeParent(selNode);
nearBlock = mEditor->GetBlockNodeParent(nearNode);
// is nearNode also a descendant of same block?
nsCOMPtr<nsIDOMNode> block, nearBlock;
if (mEditor->IsBlockNode(selNode)) block = selNode;
else block = mEditor->GetBlockNodeParent(selNode);
nearBlock = mEditor->GetBlockNodeParent(nearNode);
if (block == nearBlock)
{
// need to insert special moz BR. Why? Because if we don't
@ -3711,10 +3696,10 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
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;
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
@ -3723,16 +3708,37 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
// 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;
}
nsCOMPtr<nsIDOMNode> nextNode;
res = GetNextHTMLNode(nearNode, &nextNode);
if (NS_FAILED(res)) return res;
if (nextNode && 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;
}
else
{
// alright, not that either. But there's one more squirrel to feed:
// the br might be right in front of a new block (ie,:
// <body> text<br> <ol><li>list item</li></ol></body> )
// in this case we also need moz-br.
res = GetNextHTMLSibling(nearNode, &nextNode);
if (NS_FAILED(res)) return res;
if (nextNode && mEditor->IsBlockNode(nextNode))
{
// need to insert special moz BR. Why? Because if we don't
// the user will see no new line for the break.
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;
}
}
}
}
@ -3755,6 +3761,7 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
dir = aAction;
}
// is the nearnode a text node?
if (!nearNode) return NS_OK; // couldn't find a near text node
textNode = do_QueryInterface(nearNode);
if (!textNode) return NS_ERROR_UNEXPECTED;
PRInt32 offset = 0;
@ -3931,21 +3938,21 @@ nsHTMLEditRules::DoTextNodeWhitespace(nsIDOMCharacterData *aTextNode, PRInt32 aS
if (runStr != newStr)
{
// delete the original whitespace run
EditTxn *txn;
EditTxn *txn;
// note 1: we are not telling edit listeners about these because they don't care
// note 2: we are not wrapping these in a placeholder because we know they already are
res = mEditor->CreateTxnForDeleteText(aTextNode, aStart+runStart, runEnd-runStart, (DeleteTextTxn**)&txn);
if (NS_FAILED(res)) return res;
if (!txn) return NS_ERROR_OUT_OF_MEMORY;
if (!txn) return NS_ERROR_OUT_OF_MEMORY;
res = mEditor->Do(txn);
if (NS_FAILED(res)) return res;
// The transaction system (if any) has taken ownwership of txn
NS_IF_RELEASE(txn);
// insert the new run
res = mEditor->CreateTxnForInsertText(newStr, aTextNode, aStart+runStart, (InsertTextTxn**)&txn);
res = mEditor->CreateTxnForInsertText(newStr, aTextNode, aStart+runStart, (InsertTextTxn**)&txn);
if (NS_FAILED(res)) return res;
if (!txn) return NS_ERROR_OUT_OF_MEMORY;
if (!txn) return NS_ERROR_OUT_OF_MEMORY;
res = mEditor->Do(txn);
// The transaction system (if any) has taken ownwership of txns.
NS_IF_RELEASE(txn);
@ -4078,36 +4085,68 @@ nsHTMLEditRules::PopListItem(nsIDOMNode *aListItem, PRBool *aOutOfList)
}
// not needed for now - leaving around in case we go back to it
#if 0
nsresult
nsHTMLEditRules::AddTrailerBR(nsIDOMNode *aNode)
nsHTMLEditRules::ConfirmSelectionInBody()
{
// check parms
if (!aNode) return NS_ERROR_NULL_POINTER;
nsresult res = NS_OK;
// comfirm that this node is a type that we add trailer br's to:
// td, th, li
if (IsListItem(aNode)) // add more types later
nsCOMPtr<nsIDOMElement> bodyElement;
nsCOMPtr<nsIDOMNode> bodyNode;
// get the body
res = mEditor->GetBodyElement(getter_AddRefs(bodyElement));
if (NS_FAILED(res)) return res;
if (!bodyElement) return NS_ERROR_UNEXPECTED;
bodyNode = do_QueryInterface(bodyElement);
// get the selection
nsCOMPtr<nsIDOMSelection>selection;
res = mEditor->GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
// get the selection start location
nsCOMPtr<nsIDOMNode> selNode, temp, parent;
PRInt32 selOffset;
res = mEditor->GetStartNodeAndOffset(selection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
temp = selNode;
// check that selNode is inside body
while (temp && !IsBody(temp))
{
PRUint32 count;
nsCOMPtr<nsIDOMNode> brNode;
res = mEditor->GetLengthOfDOMNode(aNode, count);
if (NS_FAILED(res)) return res;
res = mEditor->CreateBR(aNode, count, &brNode);
if (NS_FAILED(res)) return res;
// give it special trailer attr
nsCOMPtr<nsIDOMElement> brElem = do_QueryInterface(brNode);
res = mEditor->SetAttribute(brElem, "type", "_moz_trailer");
res = temp->GetParentNode(getter_AddRefs(parent));
temp = parent;
}
else
// if we aren't in the body, force the issue
if (!temp)
{
NS_NOTREACHED("editor error: nsHTMLEditRules::AddTrailerBR() called on bad node type");
// uncomment this to see when we get bad selections
// NS_NOTREACHED("selection not in body");
selection->Collapse(bodyNode,0);
}
return res;
// get the selection end location
res = mEditor->GetEndNodeAndOffset(selection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
temp = selNode;
// check that selNode is inside body
while (temp && !IsBody(temp))
{
res = temp->GetParentNode(getter_AddRefs(parent));
temp = parent;
}
// if we aren't in the body, force the issue
if (!temp)
{
// uncomment this to see when we get bad selections
// NS_NOTREACHED("selection not in body");
selection->Collapse(bodyNode,0);
}
}
#endif
nsresult
nsHTMLEditRules::UpdateDocChangeRange(nsIDOMRange *aRange)

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

@ -156,6 +156,7 @@ protected:
nsresult UpdateDocChangeRange(nsIDOMRange *aRange);
nsresult ConvertWhitespace(const nsString & inString, nsString & outString);
nsresult ConfirmSelectionInBody();
// removed from use:
#if 0

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

@ -3639,43 +3639,48 @@ NS_IMETHODIMP nsHTMLEditor::PasteAsQuotation()
NS_IMETHODIMP nsHTMLEditor::PasteAsCitedQuotation(const nsString& aCitation)
{
nsAutoEditBatch beginBatching(this);
nsCOMPtr<nsIDOMNode> newNode;
nsAutoString tag("blockquote");
nsresult res = DeleteSelectionAndCreateNode(tag, getter_AddRefs(newNode));
if (NS_FAILED(res)) return res;
if (!newNode) return NS_ERROR_NULL_POINTER;
// Try to set type=cite. Ignore it if this fails.
nsCOMPtr<nsIDOMElement> newElement (do_QueryInterface(newNode));
if (newElement)
{
nsAutoString type ("type");
nsAutoString cite ("cite");
newElement->SetAttribute(type, cite);
}
// Set the selection to the underneath the node we just inserted:
// get selection
nsCOMPtr<nsIDOMSelection> selection;
res = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res) || !selection)
{
#ifdef DEBUG_akkana
printf("Can't get selection!");
#endif
}
nsresult res = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
if (!selection) return NS_ERROR_NULL_POINTER;
res = selection->Collapse(newNode, 0);
if (NS_FAILED(res))
// 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)
{
#ifdef DEBUG_akkana
printf("Couldn't collapse");
#endif
// XXX: error result: should res be returned here?
}
nsCOMPtr<nsIDOMNode> newNode;
nsAutoString tag("blockquote");
res = DeleteSelectionAndCreateNode(tag, getter_AddRefs(newNode));
if (NS_FAILED(res)) return res;
if (!newNode) return NS_ERROR_NULL_POINTER;
res = Paste();
// Try to set type=cite. Ignore it if this fails.
nsCOMPtr<nsIDOMElement> newElement (do_QueryInterface(newNode));
if (newElement)
{
nsAutoString type ("type");
nsAutoString cite ("cite");
newElement->SetAttribute(type, cite);
}
// Set the selection to the underneath the node we just inserted:
res = selection->Collapse(newNode, 0);
if (NS_FAILED(res))
{
#ifdef DEBUG_akkana
printf("Couldn't collapse");
#endif
// XXX: error result: should res be returned here?
}
res = Paste();
}
return res;
}
@ -3800,42 +3805,53 @@ nsHTMLEditor::InsertAsPlaintextQuotation(const nsString& aQuotedText,
nsAutoEditBatch beginBatching(this);
// Wrap the inserted quote in a <pre> so it won't be wrapped:
nsCOMPtr<nsIDOMNode> preNode;
nsAutoString tag("pre");
rv = DeleteSelectionAndCreateNode(tag, getter_AddRefs(preNode));
// If this succeeded, then set selection inside the pre
// so the inserted text will end up there.
// If it failed, we don't care what the return value was,
// but we'll fall through and try to insert the text anyway.
// get selection
nsCOMPtr<nsIDOMSelection> selection;
rv = GetSelection(getter_AddRefs(selection));
if (NS_SUCCEEDED(rv) && preNode)
{
if (NS_SUCCEEDED(rv) && selection)
selection->Collapse(preNode, 0);
}
if (NS_FAILED(rv)) return rv;
if (!selection) return NS_ERROR_NULL_POINTER;
rv = InsertText(quotedStuff);
if (aNodeInserted)
// give rules a chance to handle or cancel
nsTextRulesInfo ruleInfo(nsHTMLEditRules::kInsertElement);
PRBool cancel, handled;
rv = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
if (NS_FAILED(rv)) return rv;
if (cancel) return NS_OK; // rules canceled the operation
if (!handled)
{
if (NS_SUCCEEDED(rv))
// Wrap the inserted quote in a <pre> so it won't be wrapped:
nsCOMPtr<nsIDOMNode> preNode;
nsAutoString tag("pre");
rv = DeleteSelectionAndCreateNode(tag, getter_AddRefs(preNode));
// If this succeeded, then set selection inside the pre
// so the inserted text will end up there.
// If it failed, we don't care what the return value was,
// but we'll fall through and try to insert the text anyway.
if (NS_SUCCEEDED(rv) && preNode)
{
*aNodeInserted = preNode;
NS_IF_ADDREF(*aNodeInserted);
selection->Collapse(preNode, 0);
}
rv = InsertText(quotedStuff);
if (aNodeInserted)
{
if (NS_SUCCEEDED(rv))
{
*aNodeInserted = preNode;
NS_IF_ADDREF(*aNodeInserted);
}
}
// Set the selection to just after the inserted node:
if (NS_SUCCEEDED(rv) && preNode)
{
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
if (NS_SUCCEEDED(GetNodeLocation(preNode, &parent, &offset)) && parent)
selection->Collapse(parent, offset+1);
}
}
// Set the selection to just after the inserted node:
if (NS_SUCCEEDED(rv) && preNode)
{
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
if (NS_SUCCEEDED(GetNodeLocation(preNode, &parent, &offset)) && parent)
selection->Collapse(parent, offset+1);
}
return rv;
}
@ -3848,48 +3864,61 @@ nsHTMLEditor::InsertAsCitedQuotation(const nsString& aQuotedText,
nsAutoEditBatch beginBatching(this);
nsCOMPtr<nsIDOMNode> newNode;
nsAutoRules beginRulesSniffing(this, kOpInsertElement, nsIEditor::eNext);
nsAutoString tag("blockquote");
nsresult res = DeleteSelectionAndCreateNode(tag, getter_AddRefs(newNode));
if (NS_FAILED(res)) return res;
if (!newNode) return NS_ERROR_NULL_POINTER;
// Try to set type=cite. Ignore it if this fails.
nsCOMPtr<nsIDOMElement> newElement (do_QueryInterface(newNode));
// get selection
nsCOMPtr<nsIDOMSelection> selection;
res = GetSelection(getter_AddRefs(selection));
if (newElement)
nsresult 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)
{
nsAutoString type ("type");
nsAutoString cite ("cite");
newElement->SetAttribute(type, cite);
nsAutoString tag("blockquote");
res = DeleteSelectionAndCreateNode(tag, getter_AddRefs(newNode));
if (NS_FAILED(res)) return res;
if (!newNode) return NS_ERROR_NULL_POINTER;
if (aCitation.Length() > 0)
newElement->SetAttribute(cite, aCitation);
// Set the selection inside the blockquote so aQuotedText will go there:
if (NS_SUCCEEDED(res) && selection)
selection->Collapse(newNode, 0);
}
res = InsertHTMLWithCharset(aQuotedText, aCharset);
if (aNodeInserted)
{
if (NS_SUCCEEDED(res))
// Try to set type=cite. Ignore it if this fails.
nsCOMPtr<nsIDOMElement> newElement (do_QueryInterface(newNode));
if (newElement)
{
*aNodeInserted = newNode;
NS_IF_ADDREF(*aNodeInserted);
nsAutoString type ("type");
nsAutoString cite ("cite");
newElement->SetAttribute(type, cite);
if (aCitation.Length() > 0)
newElement->SetAttribute(cite, aCitation);
// Set the selection inside the blockquote so aQuotedText will go there:
if (NS_SUCCEEDED(res))
selection->Collapse(newNode, 0);
}
res = InsertHTMLWithCharset(aQuotedText, aCharset);
if (aNodeInserted)
{
if (NS_SUCCEEDED(res))
{
*aNodeInserted = newNode;
NS_IF_ADDREF(*aNodeInserted);
}
}
// Set the selection to just after the inserted node:
if (NS_SUCCEEDED(res) && newNode)
{
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
if (NS_SUCCEEDED(GetNodeLocation(newNode, &parent, &offset)) && parent)
selection->Collapse(parent, offset+1);
}
}
// Set the selection to just after the inserted node:
if (NS_SUCCEEDED(res) && newNode)
{
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
if (NS_SUCCEEDED(GetNodeLocation(newNode, &parent, &offset)) && parent)
selection->Collapse(parent, offset+1);
}
return res;
}
@ -4228,6 +4257,17 @@ nsHTMLEditor::EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
}
PRBool
nsHTMLEditor::CanContainTag(nsIDOMNode* aParent, const nsString &aTag)
{
// CNavDTD gives some unwanted results. We override them here.
// if parent is a list and tag is text, say "no".
if (IsListNode(aParent) && (aTag == "__moz_text"))
return PR_FALSE;
// else fall thru
return nsEditor::CanContainTag(aParent, aTag);
}
#ifdef XP_MAC
#pragma mark -
@ -5266,6 +5306,8 @@ nsHTMLEditor::SetCaretInTableCell(nsIDOMElement* aElement)
node = firstChild;
}
}
# if 0
// I've ifdef'd this out because it isn't finished and I'm not sure what the intent is.
PRInt32 offset = 0;
nsCOMPtr<nsIDOMNode>lastChild;
res = parent->GetLastChild(getter_AddRefs(lastChild));
@ -5291,13 +5333,14 @@ nsHTMLEditor::SetCaretInTableCell(nsIDOMElement* aElement)
// We have > 1 node, so set to end of content
}
}
#endif
// Set selection at beginning of deepest node
// Should we set
nsCOMPtr<nsIDOMSelection> selection;
res = GetSelection(getter_AddRefs(selection));
if (NS_SUCCEEDED(res) && selection)
if (NS_SUCCEEDED(res) && selection && firstChild)
{
res = selection->Collapse(parent, offset);
res = selection->Collapse(firstChild, 0);
if (NS_SUCCEEDED(res))
caretIsSet = PR_TRUE;
}

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

@ -244,6 +244,8 @@ public:
/* ------------ nsICSSLoaderObserver -------------- */
NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet*aSheet, PRBool aNotify);
/* ------------ nsEditor overrides ---------------- */
/** All editor operations which alter the doc should be prefaced
* with a call to StartOperation, naming the action and direction */
NS_IMETHOD StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
@ -252,6 +254,9 @@ public:
* with a call to EndOperation, naming the action and direction */
NS_IMETHOD EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
/** returns PR_TRUE if aParent can contain a child of type aTag */
PRBool CanContainTag(nsIDOMNode* aParent, const nsString &aTag);
/* ------------ Utility Routines, not part of public API -------------- */
NS_IMETHOD GetBodyStyleContext(nsIStyleContext** aStyleContext);

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

@ -299,7 +299,7 @@ nsTextEditRules::WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel)
// get the (collapsed) selection location
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
if (NS_FAILED(res)) return res;
// get next node
// get prior node
res = GetPriorHTMLNode(selNode, selOffset, &priorNode);
if (NS_SUCCEEDED(res) && priorNode && IsMozBR(priorNode))
{
@ -1014,8 +1014,6 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection,
PRBool isCollapsed;
aSelection->GetIsCollapsed(&isCollapsed);
NS_ASSERTION(PR_TRUE==isCollapsed, "selection not collapsed after delete selection.");
// if the delete selection resulted in no content
// insert a special bogus text node with a &nbsp; character in it.
if (NS_SUCCEEDED(res)) // only do this work if DeleteSelection completed successfully
{
// if we don't have an empty document, check the selection to see if any collapsing is necessary
@ -1047,7 +1045,7 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection,
{
nsCOMPtr<nsIDOMCharacterData>selectedNodeAsText;
selectedNodeAsText = do_QueryInterface(selectedNode);
if (selectedNodeAsText)
if (selectedNodeAsText && mEditor->IsEditable(selectedNode))
{
nsCOMPtr<nsIDOMNode> siblingNode;
selectedNode->GetPreviousSibling(getter_AddRefs(siblingNode));
@ -1055,7 +1053,7 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection,
{
nsCOMPtr<nsIDOMCharacterData>siblingNodeAsText;
siblingNodeAsText = do_QueryInterface(siblingNode);
if (siblingNodeAsText)
if (siblingNodeAsText && mEditor->IsEditable(siblingNode))
{
PRUint32 siblingLength; // the length of siblingNode before the join
siblingNodeAsText->GetLength(&siblingLength);
@ -1072,7 +1070,7 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection,
{
nsCOMPtr<nsIDOMCharacterData>siblingNodeAsText;
siblingNodeAsText = do_QueryInterface(siblingNode);
if (siblingNodeAsText)
if (siblingNodeAsText && mEditor->IsEditable(siblingNode))
{
PRUint32 selectedNodeLength; // the length of siblingNode before the join
selectedNodeAsText->GetLength(&selectedNodeLength);