зеркало из https://github.com/mozilla/pjs.git
fixes for:
178304 - deleting only char in text node places caret in previous block 174867 - caret in wrong place after delete-to-end in list 181898 - select into mailcite, type: inserted text is in cite r=brade; sr=kin
This commit is contained in:
Родитель
03b6da655f
Коммит
8c1895d104
|
@ -191,6 +191,7 @@ nsHTMLEditRules::nsHTMLEditRules() :
|
||||||
mDocChangeRange(nsnull)
|
mDocChangeRange(nsnull)
|
||||||
,mListenerEnabled(PR_TRUE)
|
,mListenerEnabled(PR_TRUE)
|
||||||
,mReturnInEmptyLIKillsList(PR_TRUE)
|
,mReturnInEmptyLIKillsList(PR_TRUE)
|
||||||
|
,mDidRangedDelete(PR_FALSE)
|
||||||
,mUtilRange(nsnull)
|
,mUtilRange(nsnull)
|
||||||
,mJoinOffset(0)
|
,mJoinOffset(0)
|
||||||
{
|
{
|
||||||
|
@ -289,6 +290,9 @@ nsHTMLEditRules::BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
||||||
|
|
||||||
if (!mActionNesting)
|
if (!mActionNesting)
|
||||||
{
|
{
|
||||||
|
// clear our flag about if just deleted a range
|
||||||
|
mDidRangedDelete = PR_FALSE;
|
||||||
|
|
||||||
// remember where our selection was before edit action took place:
|
// remember where our selection was before edit action took place:
|
||||||
|
|
||||||
// get selection
|
// get selection
|
||||||
|
@ -414,6 +418,16 @@ nsHTMLEditRules::AfterEditInner(PRInt32 action, nsIEditor::EDirection aDirection
|
||||||
// expand the "changed doc range" as needed
|
// expand the "changed doc range" as needed
|
||||||
res = PromoteRange(mDocChangeRange, action);
|
res = PromoteRange(mDocChangeRange, action);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
// if we did a ranged deletion, make sure we have a place to put caret.
|
||||||
|
// Note we only want to do this if the overall operation was deletion,
|
||||||
|
// not if deletion was done along the way for kOpLoadHTML, kOpInsertText, etc.
|
||||||
|
// That's why this is here rather than DidDeleteSelection().
|
||||||
|
if ((action == nsEditor::kOpDeleteSelection) && mDidRangedDelete)
|
||||||
|
{
|
||||||
|
res = InsertBRIfNeeded(selection);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
}
|
||||||
|
|
||||||
// add in any needed <br>s, and remove any unneeded ones.
|
// add in any needed <br>s, and remove any unneeded ones.
|
||||||
res = AdjustSpecialBreaks();
|
res = AdjustSpecialBreaks();
|
||||||
|
@ -1130,9 +1144,9 @@ nsHTMLEditRules::GetFormatString(nsIDOMNode *aNode, nsAString &outFormat)
|
||||||
|
|
||||||
nsCOMPtr<nsIAtom> atom = mHTMLEditor->GetTag(aNode);
|
nsCOMPtr<nsIAtom> atom = mHTMLEditor->GetTag(aNode);
|
||||||
|
|
||||||
if ( nsIEditProperty::p == atom.get() ||
|
if ( nsIEditProperty::p == atom ||
|
||||||
nsIEditProperty::address == atom.get() ||
|
nsIEditProperty::address == atom ||
|
||||||
nsIEditProperty::pre == atom.get() )
|
nsIEditProperty::pre == atom )
|
||||||
{
|
{
|
||||||
atom->ToString(format);
|
atom->ToString(format);
|
||||||
}
|
}
|
||||||
|
@ -1776,7 +1790,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
|
||||||
// initialize out param
|
// initialize out param
|
||||||
*aCancel = PR_FALSE;
|
*aCancel = PR_FALSE;
|
||||||
*aHandled = PR_FALSE;
|
*aHandled = PR_FALSE;
|
||||||
|
|
||||||
// if there is only bogus content, cancel the operation
|
// if there is only bogus content, cancel the operation
|
||||||
if (mBogusNode)
|
if (mBogusNode)
|
||||||
{
|
{
|
||||||
|
@ -1859,6 +1873,8 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
|
||||||
else
|
else
|
||||||
res = wsObj.DeleteWSBackward();
|
res = wsObj.DeleteWSBackward();
|
||||||
*aHandled = PR_TRUE;
|
*aHandled = PR_TRUE;
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = InsertBRIfNeeded(aSelection);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
else if (wsType==nsWSRunObject::eText)
|
else if (wsType==nsWSRunObject::eText)
|
||||||
|
@ -1877,12 +1893,22 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
|
||||||
nsCOMPtr<nsIDOMCharacterData> nodeAsText(do_QueryInterface(visNode));
|
nsCOMPtr<nsIDOMCharacterData> nodeAsText(do_QueryInterface(visNode));
|
||||||
res = mHTMLEditor->DeleteText(nodeAsText,so,1);
|
res = mHTMLEditor->DeleteText(nodeAsText,so,1);
|
||||||
*aHandled = PR_TRUE;
|
*aHandled = PR_TRUE;
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = InsertBRIfNeeded(aSelection);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
else if ( (wsType==nsWSRunObject::eSpecial) ||
|
else if ( (wsType==nsWSRunObject::eSpecial) ||
|
||||||
(wsType==nsWSRunObject::eBreak) ||
|
(wsType==nsWSRunObject::eBreak) ||
|
||||||
nsHTMLEditUtils::IsHR(visNode) )
|
nsHTMLEditUtils::IsHR(visNode) )
|
||||||
{
|
{
|
||||||
|
// short circuit for invisible breaks. delete them and recurse.
|
||||||
|
if (nsTextEditUtils::IsBreak(visNode) && !mHTMLEditor->IsVisBreak(visNode))
|
||||||
|
{
|
||||||
|
res = mHTMLEditor->DeleteNode(visNode);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
return WillDeleteSelection(aSelection, aAction, aCancel, aHandled);
|
||||||
|
}
|
||||||
|
|
||||||
// found break or image, or hr.
|
// found break or image, or hr.
|
||||||
res = nsWSRunObject::PrepareToDeleteNode(mHTMLEditor, visNode);
|
res = nsWSRunObject::PrepareToDeleteNode(mHTMLEditor, visNode);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
@ -1909,25 +1935,50 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
|
||||||
res = aSelection->Collapse(selNode, selOffset);
|
res = aSelection->Collapse(selNode, selOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = InsertBRIfNeeded(aSelection);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
else if (wsType==nsWSRunObject::eOtherBlock)
|
else if (wsType==nsWSRunObject::eOtherBlock)
|
||||||
{
|
{
|
||||||
// next to a block. Look inside it and see if we can join to it
|
// next to a block. See if we are between a block and a br. If so, we really
|
||||||
|
// want to delete the br. Else join content at selection to the block.
|
||||||
|
|
||||||
// first find the relavent nodes
|
PRBool bDeletedBR = PR_FALSE;
|
||||||
nsCOMPtr<nsIDOMNode> leftNode, rightNode, leftParent, rightParent;
|
PRInt16 otherWSType;
|
||||||
|
nsCOMPtr<nsIDOMNode> otherNode;
|
||||||
|
PRInt32 otherOffset;
|
||||||
|
|
||||||
|
// find node in other direction
|
||||||
|
if (aAction == nsIEditor::eNext)
|
||||||
|
res = wsObj.PriorVisibleNode(startNode, startOffset, address_of(otherNode), &otherOffset, &otherWSType);
|
||||||
|
else
|
||||||
|
res = wsObj.NextVisibleNode(startNode, startOffset, address_of(otherNode), &otherOffset, &otherWSType);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
// first find the adjacent node in the block
|
||||||
|
nsCOMPtr<nsIDOMNode> leafNode, leftNode, rightNode, leftParent, rightParent;
|
||||||
if (aAction == nsIEditor::ePrevious)
|
if (aAction == nsIEditor::ePrevious)
|
||||||
{
|
{
|
||||||
res = mHTMLEditor->GetLastEditableLeaf( visNode, address_of(leftNode));
|
res = mHTMLEditor->GetLastEditableLeaf( visNode, address_of(leafNode));
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
leftNode = leafNode;
|
||||||
rightNode = startNode;
|
rightNode = startNode;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
res = mHTMLEditor->GetFirstEditableLeaf( visNode, address_of(rightNode));
|
res = mHTMLEditor->GetFirstEditableLeaf( visNode, address_of(leafNode));
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
leftNode = startNode;
|
leftNode = startNode;
|
||||||
|
rightNode = leafNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nsTextEditUtils::IsBreak(otherNode))
|
||||||
|
{
|
||||||
|
res = mHTMLEditor->DeleteNode(otherNode);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
*aHandled = PR_TRUE;
|
||||||
|
bDeletedBR = PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// dont cross table boundaries
|
// dont cross table boundaries
|
||||||
|
@ -1935,6 +1986,19 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
|
||||||
res = InDifferentTableElements(leftNode, rightNode, &bInDifTblElems);
|
res = InDifferentTableElements(leftNode, rightNode, &bInDifTblElems);
|
||||||
if (NS_FAILED(res) || bInDifTblElems) return res;
|
if (NS_FAILED(res) || bInDifTblElems) return res;
|
||||||
|
|
||||||
|
if (bDeletedBR)
|
||||||
|
{
|
||||||
|
// put selection at edge of block and we are done.
|
||||||
|
nsCOMPtr<nsIDOMNode> newSelNode;
|
||||||
|
PRInt32 newSelOffset;
|
||||||
|
res = GetGoodSelPointForNode(leafNode, aAction, address_of(newSelNode), &newSelOffset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
aSelection->Collapse(newSelNode, newSelOffset);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// else we are joining content to block
|
||||||
|
|
||||||
// find the relavent blocks
|
// find the relavent blocks
|
||||||
if (IsBlockNode(leftNode))
|
if (IsBlockNode(leftNode))
|
||||||
leftParent = leftNode;
|
leftParent = leftNode;
|
||||||
|
@ -2022,6 +2086,9 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
|
||||||
res = ExpandSelectionForDeletion(aSelection);
|
res = ExpandSelectionForDeletion(aSelection);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
// remember that we did a ranged delete for the benefit of AfterEditInner().
|
||||||
|
mDidRangedDelete = PR_TRUE;
|
||||||
|
|
||||||
// refresh start and end points
|
// refresh start and end points
|
||||||
res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(startNode), &startOffset);
|
res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(startNode), &startOffset);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
@ -2032,7 +2099,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
if (!endNode) return NS_ERROR_FAILURE;
|
if (!endNode) return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
// figure out if the enpoints are in nodes that can be merged
|
// figure out if the endpoints are in nodes that can be merged
|
||||||
// adjust surrounding whitespace in preperation to delete selection
|
// adjust surrounding whitespace in preperation to delete selection
|
||||||
if (!bPlaintext)
|
if (!bPlaintext)
|
||||||
{
|
{
|
||||||
|
@ -2042,13 +2109,41 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
|
||||||
address_of(endNode), &endOffset);
|
address_of(endNode), &endOffset);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
}
|
||||||
if (endNode.get() != startNode.get())
|
|
||||||
{
|
{
|
||||||
{
|
// track end location of where we are deleting
|
||||||
// track end location of where we are deleting
|
nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, address_of(endNode), &endOffset);
|
||||||
nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, address_of(endNode), &endOffset);
|
// we are handling all ranged deletions directly now.
|
||||||
|
*aHandled = PR_TRUE;
|
||||||
|
|
||||||
// block parents the same? use default deletion
|
if (endNode == startNode)
|
||||||
|
{
|
||||||
|
res = mHTMLEditor->DeleteSelectionImpl(aAction);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// figure out mailcite ancestors
|
||||||
|
nsCOMPtr<nsIDOMNode> endCiteNode, startCiteNode;
|
||||||
|
res = GetTopEnclosingMailCite(startNode, address_of(startCiteNode),
|
||||||
|
mFlags & nsIPlaintextEditor::eEditorPlaintextMask);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = GetTopEnclosingMailCite(endNode, address_of(endCiteNode),
|
||||||
|
mFlags & nsIPlaintextEditor::eEditorPlaintextMask);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
// if we only have a mailcite at one of the two endpoints, set the directionality
|
||||||
|
// of the deletion so that the selection will end up outside the mailcite.
|
||||||
|
if (startCiteNode && !endCiteNode)
|
||||||
|
{
|
||||||
|
aAction = nsIEditor::eNext;
|
||||||
|
}
|
||||||
|
else if (!startCiteNode && endCiteNode)
|
||||||
|
{
|
||||||
|
aAction = nsIEditor::ePrevious;
|
||||||
|
}
|
||||||
|
|
||||||
|
// figure out block parents
|
||||||
nsCOMPtr<nsIDOMNode> leftParent;
|
nsCOMPtr<nsIDOMNode> leftParent;
|
||||||
nsCOMPtr<nsIDOMNode> rightParent;
|
nsCOMPtr<nsIDOMNode> rightParent;
|
||||||
if (IsBlockNode(startNode))
|
if (IsBlockNode(startNode))
|
||||||
|
@ -2059,132 +2154,214 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
|
||||||
rightParent = endNode;
|
rightParent = endNode;
|
||||||
else
|
else
|
||||||
rightParent = mHTMLEditor->GetBlockNodeParent(endNode);
|
rightParent = mHTMLEditor->GetBlockNodeParent(endNode);
|
||||||
if (leftParent.get() == rightParent.get()) return NS_OK;
|
|
||||||
|
// are endpoint block parents the same? use default deletion
|
||||||
// deleting across blocks
|
if (leftParent == rightParent)
|
||||||
// are the blocks of same type?
|
|
||||||
|
|
||||||
// are the blocks siblings?
|
|
||||||
nsCOMPtr<nsIDOMNode> leftBlockParent;
|
|
||||||
nsCOMPtr<nsIDOMNode> rightBlockParent;
|
|
||||||
leftParent->GetParentNode(getter_AddRefs(leftBlockParent));
|
|
||||||
rightParent->GetParentNode(getter_AddRefs(rightBlockParent));
|
|
||||||
|
|
||||||
// MOOSE: this could conceivably screw up a table.. fix me.
|
|
||||||
if ( (leftBlockParent.get() == rightBlockParent.get())
|
|
||||||
&& (mHTMLEditor->NodesSameType(leftParent, rightParent)) )
|
|
||||||
{
|
{
|
||||||
if (nsHTMLEditUtils::IsParagraph(leftParent))
|
res = mHTMLEditor->DeleteSelectionImpl(aAction);
|
||||||
{
|
|
||||||
// first delete the selection
|
|
||||||
*aHandled = PR_TRUE;
|
|
||||||
res = mHTMLEditor->DeleteSelectionImpl(aAction);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
// then join para's, insert break
|
|
||||||
res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
// fix up selection
|
|
||||||
res = aSelection->Collapse(selNode,selOffset);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
if (nsHTMLEditUtils::IsListItem(leftParent)
|
|
||||||
|| nsHTMLEditUtils::IsHeader(leftParent))
|
|
||||||
{
|
|
||||||
// first delete the selection
|
|
||||||
*aHandled = PR_TRUE;
|
|
||||||
res = mHTMLEditor->DeleteSelectionImpl(aAction);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
// join blocks
|
|
||||||
res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
// fix up selection
|
|
||||||
res = aSelection->Collapse(selNode,selOffset);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// else blocks not same type, or not siblings. Delete everything except
|
|
||||||
// table elements.
|
|
||||||
*aHandled = PR_TRUE;
|
|
||||||
nsCOMPtr<nsIEnumerator> enumerator;
|
|
||||||
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(aSelection));
|
|
||||||
res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
if (!enumerator) return NS_ERROR_UNEXPECTED;
|
|
||||||
|
|
||||||
for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next())
|
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsISupports> currentItem;
|
// deleting across blocks
|
||||||
res = enumerator->CurrentItem(getter_AddRefs(currentItem));
|
// are the blocks of same type?
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
if (!currentItem) return NS_ERROR_UNEXPECTED;
|
// are the blocks siblings?
|
||||||
|
nsCOMPtr<nsIDOMNode> leftBlockParent;
|
||||||
|
nsCOMPtr<nsIDOMNode> rightBlockParent;
|
||||||
|
leftParent->GetParentNode(getter_AddRefs(leftBlockParent));
|
||||||
|
rightParent->GetParentNode(getter_AddRefs(rightBlockParent));
|
||||||
|
|
||||||
// build a list of nodes in the range
|
// MOOSE: this could conceivably screw up a table.. fix me.
|
||||||
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
|
if ( (leftBlockParent == rightBlockParent)
|
||||||
nsCOMArray<nsIDOMNode> arrayOfNodes;
|
&& (mHTMLEditor->NodesSameType(leftParent, rightParent)) )
|
||||||
nsTrivialFunctor functor;
|
|
||||||
nsDOMSubtreeIterator iter;
|
|
||||||
res = iter.Init(range);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
res = iter.MakeList(functor, arrayOfNodes);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
|
|
||||||
// now that we have the list, delete non table elements
|
|
||||||
PRInt32 listCount = arrayOfNodes.Count();
|
|
||||||
PRInt32 j;
|
|
||||||
|
|
||||||
for (j = 0; j < listCount; j++)
|
|
||||||
{
|
{
|
||||||
nsIDOMNode* somenode = arrayOfNodes[0];
|
if (nsHTMLEditUtils::IsParagraph(leftParent))
|
||||||
res = DeleteNonTableElements(somenode);
|
{
|
||||||
arrayOfNodes.RemoveObjectAt(0);
|
// first delete the selection
|
||||||
|
res = mHTMLEditor->DeleteSelectionImpl(aAction);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
// then join para's, insert break
|
||||||
|
res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
// fix up selection
|
||||||
|
res = aSelection->Collapse(selNode,selOffset);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if (nsHTMLEditUtils::IsListItem(leftParent)
|
||||||
|
|| nsHTMLEditUtils::IsHeader(leftParent))
|
||||||
|
{
|
||||||
|
// first delete the selection
|
||||||
|
res = mHTMLEditor->DeleteSelectionImpl(aAction);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
// join blocks
|
||||||
|
res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
// fix up selection
|
||||||
|
res = aSelection->Collapse(selNode,selOffset);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// else blocks not same type, or not siblings. Delete everything except
|
||||||
|
// table elements.
|
||||||
|
nsCOMPtr<nsIEnumerator> enumerator;
|
||||||
|
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(aSelection));
|
||||||
|
res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
if (!enumerator) return NS_ERROR_UNEXPECTED;
|
||||||
|
|
||||||
|
for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next())
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsISupports> currentItem;
|
||||||
|
res = enumerator->CurrentItem(getter_AddRefs(currentItem));
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
if (!currentItem) return NS_ERROR_UNEXPECTED;
|
||||||
|
|
||||||
|
// build a list of nodes in the range
|
||||||
|
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
|
||||||
|
nsCOMArray<nsIDOMNode> arrayOfNodes;
|
||||||
|
nsTrivialFunctor functor;
|
||||||
|
nsDOMSubtreeIterator iter;
|
||||||
|
res = iter.Init(range);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = iter.MakeList(functor, arrayOfNodes);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
// check endopints for possible text deletion.
|
// now that we have the list, delete non table elements
|
||||||
// we can assume that if text node is found, we can
|
PRInt32 listCount = arrayOfNodes.Count();
|
||||||
// delete to end or to begining as appropriate,
|
PRInt32 j;
|
||||||
// since the case where both sel endpoints in same
|
|
||||||
// text node was already handled (we wouldn't be here)
|
for (j = 0; j < listCount; j++)
|
||||||
if ( mHTMLEditor->IsTextNode(startNode) )
|
{
|
||||||
{
|
nsIDOMNode* somenode = arrayOfNodes[0];
|
||||||
// delete to last character
|
res = DeleteNonTableElements(somenode);
|
||||||
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
arrayOfNodes.RemoveObjectAt(0);
|
||||||
PRUint32 len;
|
}
|
||||||
nodeAsText = do_QueryInterface(startNode);
|
|
||||||
nodeAsText->GetLength(&len);
|
|
||||||
if (len > (PRUint32)startOffset)
|
|
||||||
{
|
|
||||||
res = mHTMLEditor->DeleteText(nodeAsText,startOffset,len-startOffset);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if ( mHTMLEditor->IsTextNode(endNode) )
|
// check endopints for possible text deletion.
|
||||||
{
|
// we can assume that if text node is found, we can
|
||||||
// delete to first character
|
// delete to end or to begining as appropriate,
|
||||||
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
// since the case where both sel endpoints in same
|
||||||
nodeAsText = do_QueryInterface(endNode);
|
// text node was already handled (we wouldn't be here)
|
||||||
if (endOffset)
|
if ( mHTMLEditor->IsTextNode(startNode) )
|
||||||
{
|
{
|
||||||
res = mHTMLEditor->DeleteText(nodeAsText,0,endOffset);
|
// delete to last character
|
||||||
if (NS_FAILED(res)) return res;
|
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
||||||
|
PRUint32 len;
|
||||||
|
nodeAsText = do_QueryInterface(startNode);
|
||||||
|
nodeAsText->GetLength(&len);
|
||||||
|
if (len > (PRUint32)startOffset)
|
||||||
|
{
|
||||||
|
res = mHTMLEditor->DeleteText(nodeAsText,startOffset,len-startOffset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( mHTMLEditor->IsTextNode(endNode) )
|
||||||
|
{
|
||||||
|
// delete to first character
|
||||||
|
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
||||||
|
nodeAsText = do_QueryInterface(endNode);
|
||||||
|
if (endOffset)
|
||||||
|
{
|
||||||
|
res = mHTMLEditor->DeleteText(nodeAsText,0,endOffset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (aAction == nsIEditor::eNext)
|
|
||||||
{
|
|
||||||
res = aSelection->Collapse(endNode,endOffset);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
res = aSelection->Collapse(startNode,startOffset);
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
}
|
||||||
|
if (aAction == nsIEditor::eNext)
|
||||||
|
{
|
||||||
|
res = aSelection->Collapse(endNode,endOffset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = aSelection->Collapse(startNode,startOffset);
|
||||||
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************************************
|
||||||
|
* InsertBRIfNeeded: determines if a br is needed for current selection to not be spastic.
|
||||||
|
* If so, it inserts one. Callers responsibility to only call with collapsed selection.
|
||||||
|
* nsISelection *aSelection the collapsed selection
|
||||||
|
*/
|
||||||
|
nsresult
|
||||||
|
nsHTMLEditRules::InsertBRIfNeeded(nsISelection *aSelection)
|
||||||
|
{
|
||||||
|
if (!aSelection)
|
||||||
|
return NS_ERROR_NULL_POINTER;
|
||||||
|
|
||||||
|
// get selection
|
||||||
|
nsCOMPtr<nsIDOMNode> node;
|
||||||
|
PRInt32 offset;
|
||||||
|
nsresult res = mEditor->GetStartNodeAndOffset(aSelection, address_of(node), &offset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
if (!node) return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
|
// examine selection
|
||||||
|
nsWSRunObject wsObj(mHTMLEditor, node, offset);
|
||||||
|
if (((wsObj.mStartReason & nsWSRunObject::eBlock) || (wsObj.mStartReason & nsWSRunObject::eBreak))
|
||||||
|
&& (wsObj.mEndReason & nsWSRunObject::eBlock))
|
||||||
|
{
|
||||||
|
// if we are tucked between block boundaries then insert a br
|
||||||
|
// first check that we are allowed to
|
||||||
|
if (mHTMLEditor->CanContainTag(node, NS_LITERAL_STRING("br")))
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIDOMNode> brNode;
|
||||||
|
res = mHTMLEditor->CreateBR(node, offset, address_of(brNode), nsIEditor::ePrevious);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************************************
|
||||||
|
* GetGoodSelPointForNode: Finds where at a node you would want to set the selection if you were
|
||||||
|
* trying to have a caret next to it.
|
||||||
|
* nsIDOMNode *aNode the node
|
||||||
|
* nsIEditor::EDirection aAction which edge to find: eNext indicates beginning, ePrevious ending
|
||||||
|
* nsCOMPtr<nsIDOMNode> *outSelNode desired sel node
|
||||||
|
* PRInt32 *outSelOffset desired sel offset
|
||||||
|
*/
|
||||||
|
nsresult
|
||||||
|
nsHTMLEditRules::GetGoodSelPointForNode(nsIDOMNode *aNode, nsIEditor::EDirection aAction,
|
||||||
|
nsCOMPtr<nsIDOMNode> *outSelNode, PRInt32 *outSelOffset)
|
||||||
|
{
|
||||||
|
if (!aNode || !outSelNode || !outSelOffset)
|
||||||
|
return NS_ERROR_NULL_POINTER;
|
||||||
|
|
||||||
|
nsresult res = NS_OK;
|
||||||
|
|
||||||
|
// default values
|
||||||
|
*outSelNode = aNode;
|
||||||
|
*outSelOffset = 0;
|
||||||
|
|
||||||
|
if (mHTMLEditor->IsTextNode(aNode) || mHTMLEditor->IsContainer(aNode))
|
||||||
|
{
|
||||||
|
if (aAction == nsIEditor::ePrevious)
|
||||||
|
{
|
||||||
|
PRUint32 len;
|
||||||
|
res = mHTMLEditor->GetLengthOfDOMNode(aNode, len);
|
||||||
|
*outSelOffset = PRInt32(len);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = nsEditor::GetNodeLocation(aNode, outSelNode, outSelOffset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
if (!nsTextEditUtils::IsBreak(aNode) || mHTMLEditor->IsVisBreak(aNode))
|
||||||
|
{
|
||||||
|
if (aAction == nsIEditor::ePrevious)
|
||||||
|
(*outSelOffset)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************************************
|
/*****************************************************************************************************
|
||||||
* JoinBlocks: this method is used to join two block elements. The right element is always joined
|
* JoinBlocks: this method is used to join two block elements. The right element is always joined
|
||||||
* to the left element. If the elements are the same type and not nested within each other,
|
* to the left element. If the elements are the same type and not nested within each other,
|
||||||
|
@ -4457,8 +4634,8 @@ nsHTMLEditRules::ExpandSelectionForDeletion(nsISelection *aSelection)
|
||||||
|
|
||||||
// set up for loops and cache our root element
|
// set up for loops and cache our root element
|
||||||
PRBool stillLooking = PR_TRUE;
|
PRBool stillLooking = PR_TRUE;
|
||||||
nsCOMPtr<nsIDOMNode> visNode;
|
nsCOMPtr<nsIDOMNode> visNode, firstBRParent;
|
||||||
PRInt32 visOffset=0;
|
PRInt32 visOffset=0, firstBROffset=0;
|
||||||
PRInt16 wsType;
|
PRInt16 wsType;
|
||||||
nsCOMPtr<nsIDOMElement> rootElement;
|
nsCOMPtr<nsIDOMElement> rootElement;
|
||||||
res = mHTMLEditor->GetRootElement(getter_AddRefs(rootElement));
|
res = mHTMLEditor->GetRootElement(getter_AddRefs(rootElement));
|
||||||
|
@ -4510,6 +4687,11 @@ nsHTMLEditRules::ExpandSelectionForDeletion(nsISelection *aSelection)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (!firstBRParent)
|
||||||
|
{
|
||||||
|
firstBRParent = selEndNode;
|
||||||
|
firstBROffset = selEndOffset;
|
||||||
|
}
|
||||||
nsEditor::GetNodeLocation(wsObj.mEndReasonNode, address_of(selEndNode), &selEndOffset);
|
nsEditor::GetNodeLocation(wsObj.mEndReasonNode, address_of(selEndNode), &selEndOffset);
|
||||||
++selEndOffset;
|
++selEndOffset;
|
||||||
}
|
}
|
||||||
|
@ -4519,7 +4701,8 @@ nsHTMLEditRules::ExpandSelectionForDeletion(nsISelection *aSelection)
|
||||||
// we want to keep looking up. But stop if we are crossing table element
|
// we want to keep looking up. But stop if we are crossing table element
|
||||||
// boundaries, or if we hit the root.
|
// boundaries, or if we hit the root.
|
||||||
if ( nsHTMLEditUtils::IsTableElement(wsObj.mEndReasonNode) ||
|
if ( nsHTMLEditUtils::IsTableElement(wsObj.mEndReasonNode) ||
|
||||||
(rootElement == wsObj.mEndReasonNode))
|
(selCommon == wsObj.mEndReasonNode) ||
|
||||||
|
(rootElement == wsObj.mEndReasonNode) )
|
||||||
{
|
{
|
||||||
stillLooking = PR_FALSE;
|
stillLooking = PR_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -4537,7 +4720,44 @@ nsHTMLEditRules::ExpandSelectionForDeletion(nsISelection *aSelection)
|
||||||
}
|
}
|
||||||
// now set the selection to the new range
|
// now set the selection to the new range
|
||||||
aSelection->Collapse(selStartNode, selStartOffset);
|
aSelection->Collapse(selStartNode, selStartOffset);
|
||||||
aSelection->Extend(selEndNode, selEndOffset);
|
|
||||||
|
// expand selection endpoint only if we didnt pass a br,
|
||||||
|
// or if we really needed to pass that br (ie, it's block is now
|
||||||
|
// totally selected)
|
||||||
|
PRBool doEndExpansion = PR_TRUE;
|
||||||
|
if (firstBRParent)
|
||||||
|
{
|
||||||
|
// find block node containing br
|
||||||
|
nsCOMPtr<nsIDOMNode> brBlock = firstBRParent;
|
||||||
|
if (!IsBlockNode(brBlock))
|
||||||
|
brBlock = nsHTMLEditor::GetBlockNodeParent(brBlock);
|
||||||
|
PRBool nodeBefore=PR_FALSE, nodeAfter=PR_FALSE;
|
||||||
|
|
||||||
|
// create a range that represents expanded selection
|
||||||
|
nsCOMPtr<nsIDOMRange> range = do_CreateInstance(kRangeCID);
|
||||||
|
if (!range) return NS_ERROR_NULL_POINTER;
|
||||||
|
res = range->SetStart(selStartNode, selStartOffset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = range->SetEnd(selEndNode, selEndOffset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
// check if block is entirely inside range
|
||||||
|
nsCOMPtr<nsIContent> brContentBlock = do_QueryInterface(brBlock);
|
||||||
|
res = mHTMLEditor->mRangeHelper->CompareNodeToRange(brContentBlock, range, &nodeBefore, &nodeAfter);
|
||||||
|
|
||||||
|
// if block isn't contained, forgo grabbing the br in the expanded selection
|
||||||
|
if (nodeBefore || nodeAfter)
|
||||||
|
doEndExpansion = PR_FALSE;
|
||||||
|
}
|
||||||
|
if (doEndExpansion)
|
||||||
|
{
|
||||||
|
res = aSelection->Extend(selEndNode, selEndOffset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// only expand to just before br
|
||||||
|
res = aSelection->Extend(firstBRParent, firstBROffset);
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -4557,7 +4777,7 @@ nsHTMLEditRules::AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *
|
||||||
if (NS_FAILED(res)) return PR_TRUE;
|
if (NS_FAILED(res)) return PR_TRUE;
|
||||||
if (!priorNode) return PR_TRUE;
|
if (!priorNode) return PR_TRUE;
|
||||||
nsCOMPtr<nsIDOMNode> blockParent = mHTMLEditor->GetBlockNodeParent(priorNode);
|
nsCOMPtr<nsIDOMNode> blockParent = mHTMLEditor->GetBlockNodeParent(priorNode);
|
||||||
if (blockParent && (blockParent.get() == aBlock)) return PR_FALSE;
|
if (blockParent && (blockParent == aBlock)) return PR_FALSE;
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4580,7 +4800,7 @@ nsHTMLEditRules::AtEndOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aB
|
||||||
if (NS_FAILED(res)) return PR_TRUE;
|
if (NS_FAILED(res)) return PR_TRUE;
|
||||||
if (!nextNode) return PR_TRUE;
|
if (!nextNode) return PR_TRUE;
|
||||||
nsCOMPtr<nsIDOMNode> blockParent = mHTMLEditor->GetBlockNodeParent(nextNode);
|
nsCOMPtr<nsIDOMNode> blockParent = mHTMLEditor->GetBlockNodeParent(nextNode);
|
||||||
if (blockParent && (blockParent.get() == aBlock)) return PR_FALSE;
|
if (blockParent && (blockParent == aBlock)) return PR_FALSE;
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7229,7 +7449,7 @@ nsHTMLEditRules::SelectionEndpointInNode(nsIDOMNode *aNode, PRBool *aResult)
|
||||||
range->GetStartContainer(getter_AddRefs(startParent));
|
range->GetStartContainer(getter_AddRefs(startParent));
|
||||||
if (startParent)
|
if (startParent)
|
||||||
{
|
{
|
||||||
if (aNode == startParent.get())
|
if (aNode == startParent)
|
||||||
{
|
{
|
||||||
*aResult = PR_TRUE;
|
*aResult = PR_TRUE;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -7244,7 +7464,7 @@ nsHTMLEditRules::SelectionEndpointInNode(nsIDOMNode *aNode, PRBool *aResult)
|
||||||
if (startParent == endParent) continue;
|
if (startParent == endParent) continue;
|
||||||
if (endParent)
|
if (endParent)
|
||||||
{
|
{
|
||||||
if (aNode == endParent.get())
|
if (aNode == endParent)
|
||||||
{
|
{
|
||||||
*aResult = PR_TRUE;
|
*aResult = PR_TRUE;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
|
@ -137,6 +137,9 @@ protected:
|
||||||
nsresult DidDeleteSelection(nsISelection *aSelection,
|
nsresult DidDeleteSelection(nsISelection *aSelection,
|
||||||
nsIEditor::EDirection aDir,
|
nsIEditor::EDirection aDir,
|
||||||
nsresult aResult);
|
nsresult aResult);
|
||||||
|
nsresult InsertBRIfNeeded(nsISelection *aSelection);
|
||||||
|
nsresult GetGoodSelPointForNode(nsIDOMNode *aNode, nsIEditor::EDirection aAction,
|
||||||
|
nsCOMPtr<nsIDOMNode> *outSelNode, PRInt32 *outSelOffset);
|
||||||
nsresult JoinBlocks(nsCOMPtr<nsIDOMNode> *aLeftBlock, nsCOMPtr<nsIDOMNode> *aRightBlock, PRBool *aCanceled);
|
nsresult JoinBlocks(nsCOMPtr<nsIDOMNode> *aLeftBlock, nsCOMPtr<nsIDOMNode> *aRightBlock, PRBool *aCanceled);
|
||||||
nsresult MoveBlock(nsIDOMNode *aLeft, nsIDOMNode *aRight, PRInt32 aLeftOffset, PRInt32 aRightOffset);
|
nsresult MoveBlock(nsIDOMNode *aLeft, nsIDOMNode *aRight, PRInt32 aLeftOffset, PRInt32 aRightOffset);
|
||||||
nsresult MoveNodeSmart(nsIDOMNode *aSource, nsIDOMNode *aDest, PRInt32 *aOffset);
|
nsresult MoveNodeSmart(nsIDOMNode *aSource, nsIDOMNode *aDest, PRInt32 *aOffset);
|
||||||
|
@ -263,8 +266,9 @@ protected:
|
||||||
protected:
|
protected:
|
||||||
nsHTMLEditor *mHTMLEditor;
|
nsHTMLEditor *mHTMLEditor;
|
||||||
nsCOMPtr<nsIDOMRange> mDocChangeRange;
|
nsCOMPtr<nsIDOMRange> mDocChangeRange;
|
||||||
PRBool mListenerEnabled;
|
PRPackedBool mListenerEnabled;
|
||||||
PRBool mReturnInEmptyLIKillsList;
|
PRPackedBool mReturnInEmptyLIKillsList;
|
||||||
|
PRPackedBool mDidRangedDelete;
|
||||||
nsCOMPtr<nsIDOMRange> mUtilRange;
|
nsCOMPtr<nsIDOMRange> mUtilRange;
|
||||||
PRUint32 mJoinOffset; // need to remember an int across willJoin/didJoin...
|
PRUint32 mJoinOffset; // need to remember an int across willJoin/didJoin...
|
||||||
nsCOMPtr<nsIDOMNode> mNewBlock;
|
nsCOMPtr<nsIDOMNode> mNewBlock;
|
||||||
|
|
|
@ -283,14 +283,14 @@ class nsAutoLockListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
nsAutoLockListener(PRBool *enabled) : mEnabled(enabled)
|
nsAutoLockListener(PRPackedBool *enabled) : mEnabled(enabled)
|
||||||
{if (mEnabled) { mOldState=*mEnabled; *mEnabled = PR_FALSE;}}
|
{if (mEnabled) { mOldState=*mEnabled; *mEnabled = PR_FALSE;}}
|
||||||
~nsAutoLockListener()
|
~nsAutoLockListener()
|
||||||
{if (mEnabled) *mEnabled = mOldState;}
|
{if (mEnabled) *mEnabled = mOldState;}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PRBool *mEnabled;
|
PRPackedBool *mEnabled;
|
||||||
PRBool mOldState;
|
PRPackedBool mOldState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче