зеркало из https://github.com/mozilla/gecko-dev.git
fixes:
* 113691 : Composer freezes when removing multiple ol or ul tags. * 113290 : Freezes when deleting some formatted text. * 112144 : Attempt to reply to mail freezes entire Mozilla. * 103685 : Caret disappears after deleting a blockquote w/ paragraph style. * 121282 : Pressing enter causes caret to jump from end of <p> to the<h1>. * 117418 : rewrote some code in nsWSRunObject.cpp: fixed warnings in GetWSNodes(). * 114911 : can't join two lists using delete key. * 120000 : Indent list inside table causes table to split. r=fm;sr=kin
This commit is contained in:
Родитель
5eab47f3cb
Коммит
d5f3c6a9c2
|
@ -86,6 +86,7 @@
|
||||||
const static PRUnichar nbsp = 160;
|
const static PRUnichar nbsp = 160;
|
||||||
|
|
||||||
static NS_DEFINE_IID(kContentIteratorCID, NS_CONTENTITERATOR_CID);
|
static NS_DEFINE_IID(kContentIteratorCID, NS_CONTENTITERATOR_CID);
|
||||||
|
static NS_DEFINE_IID(kLeafIteratorCID, NS_LEAFITERATOR_CID);
|
||||||
static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
|
static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
|
||||||
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
|
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
|
||||||
|
|
||||||
|
@ -140,15 +141,15 @@ class nsEmptyFunctor : public nsBoolDomIterFunctor
|
||||||
nsEmptyFunctor(nsHTMLEditor* editor) : mHTMLEditor(editor) {}
|
nsEmptyFunctor(nsHTMLEditor* editor) : mHTMLEditor(editor) {}
|
||||||
virtual PRBool operator()(nsIDOMNode* aNode) // used to build list of empty li's and td's
|
virtual PRBool operator()(nsIDOMNode* aNode) // used to build list of empty li's and td's
|
||||||
{
|
{
|
||||||
PRBool bIsEmptyNode;
|
if (nsHTMLEditUtils::IsListItem(aNode) || nsHTMLEditUtils::IsTableCellOrCaption(aNode))
|
||||||
nsresult res = mHTMLEditor->IsEmptyNode(aNode, &bIsEmptyNode, PR_FALSE, PR_FALSE);
|
|
||||||
if (NS_FAILED(res)) return PR_FALSE;
|
|
||||||
if (bIsEmptyNode
|
|
||||||
&& (nsHTMLEditUtils::IsListItem(aNode) || nsHTMLEditUtils::IsTableCellOrCaption(aNode)))
|
|
||||||
{
|
{
|
||||||
return PR_TRUE;
|
PRBool bIsEmptyNode;
|
||||||
|
nsresult res = mHTMLEditor->IsEmptyNode(aNode, &bIsEmptyNode, PR_FALSE, PR_FALSE);
|
||||||
|
if (NS_FAILED(res)) return PR_FALSE;
|
||||||
|
if (bIsEmptyNode)
|
||||||
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
nsHTMLEditor* mHTMLEditor;
|
nsHTMLEditor* mHTMLEditor;
|
||||||
|
@ -2180,7 +2181,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
|
||||||
* 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,
|
||||||
* JoinNodesSmart is called (example, joining two list items together into one). If the elements
|
* JoinNodesSmart is called (example, joining two list items together into one). If the elements
|
||||||
* are not the same type, or one is a ddescendant of the other, we instead destroy the right block
|
* are not the same type, or one is a descendant of the other, we instead destroy the right block
|
||||||
* placing it's children into leftblock. DTD containment rules are followed throughout.
|
* placing it's children into leftblock. DTD containment rules are followed throughout.
|
||||||
* nsISelection *aSelection the selection.
|
* nsISelection *aSelection the selection.
|
||||||
* nsCOMPtr<nsIDOMNode> *aLeftBlock pointer to the left block
|
* nsCOMPtr<nsIDOMNode> *aLeftBlock pointer to the left block
|
||||||
|
@ -2199,11 +2200,38 @@ nsHTMLEditRules::JoinBlocks(nsISelection *aSelection, nsCOMPtr<nsIDOMNode> *aLef
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// special rule here: if we are trying to join list items, and they are in different lists,
|
||||||
|
// join the lists instead.
|
||||||
|
PRBool bMergeLists = PR_FALSE;
|
||||||
|
nsAutoString existingListStr;
|
||||||
|
PRInt32 theOffset;
|
||||||
|
nsCOMPtr<nsIDOMNode> leftList, rightList;
|
||||||
|
if (nsHTMLEditUtils::IsListItem(*aLeftBlock) && nsHTMLEditUtils::IsListItem(*aRightBlock))
|
||||||
|
{
|
||||||
|
(*aLeftBlock)->GetParentNode(getter_AddRefs(leftList));
|
||||||
|
(*aRightBlock)->GetParentNode(getter_AddRefs(rightList));
|
||||||
|
if (leftList && rightList && (leftList!=rightList))
|
||||||
|
{
|
||||||
|
// there are some special complications if the lists are descendants of
|
||||||
|
// the other lists' items. Note that it is ok for them to be descendants
|
||||||
|
// of the other lists themselves, which is the usual case for sublists
|
||||||
|
// in our impllementation.
|
||||||
|
if (!nsHTMLEditUtils::IsDescendantOf(leftList, *aRightBlock, &theOffset) &&
|
||||||
|
!nsHTMLEditUtils::IsDescendantOf(rightList, *aLeftBlock, &theOffset))
|
||||||
|
{
|
||||||
|
*aLeftBlock = leftList;
|
||||||
|
*aRightBlock = rightList;
|
||||||
|
bMergeLists = PR_TRUE;
|
||||||
|
mHTMLEditor->GetTagString(leftList, existingListStr);
|
||||||
|
ToLowerCase(existingListStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
|
nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
|
||||||
|
|
||||||
nsresult res = NS_OK;
|
nsresult res = NS_OK;
|
||||||
|
|
||||||
PRInt32 theOffset;
|
|
||||||
// theOffset below is where you find yourself in aRightBlock when you traverse upwards
|
// theOffset below is where you find yourself in aRightBlock when you traverse upwards
|
||||||
// from aLeftBlock
|
// from aLeftBlock
|
||||||
if (nsHTMLEditUtils::IsDescendantOf(*aLeftBlock, *aRightBlock, &theOffset))
|
if (nsHTMLEditUtils::IsDescendantOf(*aLeftBlock, *aRightBlock, &theOffset))
|
||||||
|
@ -2219,7 +2247,26 @@ nsHTMLEditRules::JoinBlocks(nsISelection *aSelection, nsCOMPtr<nsIDOMNode> *aLef
|
||||||
nsCOMPtr<nsIDOMNode> brNode;
|
nsCOMPtr<nsIDOMNode> brNode;
|
||||||
res = CheckForInvisibleBR(*aLeftBlock, kBlockEnd, address_of(brNode));
|
res = CheckForInvisibleBR(*aLeftBlock, kBlockEnd, address_of(brNode));
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
res = MoveBlock(aSelection, *aLeftBlock, -1);
|
if (bMergeLists)
|
||||||
|
{
|
||||||
|
// idea here is to take all list items and sublists in rightList that are past
|
||||||
|
// theOffset, and pull them into leftlist.
|
||||||
|
nsCOMPtr<nsIDOMNode> childToMove;
|
||||||
|
nsCOMPtr<nsIContent> parent(do_QueryInterface(rightList)), child;
|
||||||
|
if (!parent) return NS_ERROR_NULL_POINTER;
|
||||||
|
parent->ChildAt(theOffset, *getter_AddRefs(child));
|
||||||
|
while (child)
|
||||||
|
{
|
||||||
|
childToMove = do_QueryInterface(child);
|
||||||
|
res = mHTMLEditor->MoveNode(childToMove, leftList, -1);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
parent->ChildAt(theOffset, *getter_AddRefs(child));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = MoveBlock(aSelection, *aLeftBlock, -1);
|
||||||
|
}
|
||||||
if (brNode) mHTMLEditor->DeleteNode(brNode);
|
if (brNode) mHTMLEditor->DeleteNode(brNode);
|
||||||
}
|
}
|
||||||
// theOffset below is where you find yourself in aLeftBlock when you traverse upwards
|
// theOffset below is where you find yourself in aLeftBlock when you traverse upwards
|
||||||
|
@ -2236,7 +2283,14 @@ nsHTMLEditRules::JoinBlocks(nsISelection *aSelection, nsCOMPtr<nsIDOMNode> *aLef
|
||||||
nsCOMPtr<nsIDOMNode> brNode;
|
nsCOMPtr<nsIDOMNode> brNode;
|
||||||
res = CheckForInvisibleBR(*aLeftBlock, kBeforeBlock, address_of(brNode), theOffset);
|
res = CheckForInvisibleBR(*aLeftBlock, kBeforeBlock, address_of(brNode), theOffset);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
res = MoveBlock(aSelection, *aLeftBlock, theOffset);
|
if (bMergeLists)
|
||||||
|
{
|
||||||
|
res = MoveContents(rightList, leftList, &theOffset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = MoveBlock(aSelection, *aLeftBlock, theOffset);
|
||||||
|
}
|
||||||
if (brNode) mHTMLEditor->DeleteNode(brNode);
|
if (brNode) mHTMLEditor->DeleteNode(brNode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2253,12 +2307,15 @@ nsHTMLEditRules::JoinBlocks(nsISelection *aSelection, nsCOMPtr<nsIDOMNode> *aLef
|
||||||
nsCOMPtr<nsIDOMNode> brNode;
|
nsCOMPtr<nsIDOMNode> brNode;
|
||||||
res = CheckForInvisibleBR(*aLeftBlock, kBlockEnd, address_of(brNode));
|
res = CheckForInvisibleBR(*aLeftBlock, kBlockEnd, address_of(brNode));
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
if (mHTMLEditor->NodesSameType(*aLeftBlock, *aRightBlock))
|
if (bMergeLists || mHTMLEditor->NodesSameType(*aLeftBlock, *aRightBlock))
|
||||||
{
|
{
|
||||||
// nodes are same type. merge them.
|
// nodes are same type. merge them.
|
||||||
nsCOMPtr<nsIDOMNode> parent;
|
nsCOMPtr<nsIDOMNode> parent;
|
||||||
PRInt32 offset;
|
PRInt32 offset;
|
||||||
res = JoinNodesSmart(*aLeftBlock, *aRightBlock, address_of(parent), &offset);
|
res = JoinNodesSmart(*aLeftBlock, *aRightBlock, address_of(parent), &offset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
nsCOMPtr<nsIDOMNode> newBlock;
|
||||||
|
res = ConvertListType(*aRightBlock, address_of(newBlock), existingListStr, NS_LITERAL_STRING("li"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3138,7 +3195,6 @@ nsresult
|
||||||
nsHTMLEditRules::WillHTMLIndent(nsISelection *aSelection, PRBool *aCancel, PRBool * aHandled)
|
nsHTMLEditRules::WillHTMLIndent(nsISelection *aSelection, PRBool *aCancel, PRBool * aHandled)
|
||||||
{
|
{
|
||||||
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
||||||
|
|
||||||
nsresult res = WillInsert(aSelection, aCancel);
|
nsresult res = WillInsert(aSelection, aCancel);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
@ -3211,10 +3267,14 @@ nsHTMLEditRules::WillHTMLIndent(nsISelection *aSelection, PRBool *aCancel, PRBoo
|
||||||
// here's where we actually figure out what to do
|
// here's where we actually figure out what to do
|
||||||
nsCOMPtr<nsISupports> isupports = dont_AddRef(arrayOfNodes->ElementAt(i));
|
nsCOMPtr<nsISupports> isupports = dont_AddRef(arrayOfNodes->ElementAt(i));
|
||||||
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
|
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
|
||||||
|
|
||||||
|
// Ignore all non-editable nodes. Leave them be.
|
||||||
|
if (!mHTMLEditor->IsEditable(curNode)) continue;
|
||||||
|
|
||||||
PRInt32 offset;
|
PRInt32 offset;
|
||||||
res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
|
res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
// some logic for putting list items into nested lists...
|
// some logic for putting list items into nested lists...
|
||||||
if (nsHTMLEditUtils::IsList(curParent))
|
if (nsHTMLEditUtils::IsList(curParent))
|
||||||
{
|
{
|
||||||
|
@ -3243,6 +3303,8 @@ nsHTMLEditRules::WillHTMLIndent(nsISelection *aSelection, PRBool *aCancel, PRBoo
|
||||||
// tuck the node into the end of the active list
|
// tuck the node into the end of the active list
|
||||||
res = mHTMLEditor->MoveNode(curNode, curList, -1);
|
res = mHTMLEditor->MoveNode(curNode, curList, -1);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
// forget curQuote, if any
|
||||||
|
curQuote = nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
else // not a list item, use blockquote?
|
else // not a list item, use blockquote?
|
||||||
|
@ -3518,8 +3580,10 @@ nsHTMLEditRules::WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool *
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// ConvertListType: convert list type and list item type.
|
// RemovePartOfBlock: split aBlock and move aStartChild to aEndChild out
|
||||||
//
|
// of aBlock. return left side of block (if any) in
|
||||||
|
// aLeftNode. return right side of block (if any) in
|
||||||
|
// aRightNode.
|
||||||
//
|
//
|
||||||
nsresult
|
nsresult
|
||||||
nsHTMLEditRules::RemovePartOfBlock(nsIDOMNode *aBlock,
|
nsHTMLEditRules::RemovePartOfBlock(nsIDOMNode *aBlock,
|
||||||
|
@ -3581,7 +3645,7 @@ nsHTMLEditRules::ConvertListType(nsIDOMNode *aList,
|
||||||
const nsAReadableString& aItemType)
|
const nsAReadableString& aItemType)
|
||||||
{
|
{
|
||||||
if (!aList || !outList) return NS_ERROR_NULL_POINTER;
|
if (!aList || !outList) return NS_ERROR_NULL_POINTER;
|
||||||
*outList = aList; // we migvht not need to change the list
|
*outList = aList; // we might not need to change the list
|
||||||
nsresult res = NS_OK;
|
nsresult res = NS_OK;
|
||||||
nsCOMPtr<nsIDOMNode> child, temp;
|
nsCOMPtr<nsIDOMNode> child, temp;
|
||||||
aList->GetFirstChild(getter_AddRefs(child));
|
aList->GetFirstChild(getter_AddRefs(child));
|
||||||
|
@ -4224,13 +4288,16 @@ nsHTMLEditRules::CheckForInvisibleBR(nsIDOMNode *aBlock,
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// GetInnerContent: aList and aTbl allow the caller to specify what kind
|
// GetInnerContent: aList and aTbl allow the caller to specify what kind
|
||||||
// of content to "look inside". If aTbl is true, look inside
|
// of content to "look inside". If aTbl is true, look inside
|
||||||
// any table content, and append the inner content to the
|
// any table content, and insert the inner content into the
|
||||||
// supplied issupportsarray. Similarly with aList and list content.
|
// supplied issupportsarray at offset aIndex.
|
||||||
|
// Similarly with aList and list content.
|
||||||
|
// aIndex is updated to point past inserted elements.
|
||||||
//
|
//
|
||||||
nsresult
|
nsresult
|
||||||
nsHTMLEditRules::GetInnerContent(nsIDOMNode *aNode, nsISupportsArray *outArrayOfNodes, PRBool aList, PRBool aTbl)
|
nsHTMLEditRules::GetInnerContent(nsIDOMNode *aNode, nsISupportsArray *outArrayOfNodes,
|
||||||
|
PRInt32 *aIndex, PRBool aList, PRBool aTbl)
|
||||||
{
|
{
|
||||||
if (!aNode || !outArrayOfNodes) return NS_ERROR_NULL_POINTER;
|
if (!aNode || !outArrayOfNodes || !aIndex) return NS_ERROR_NULL_POINTER;
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMNode> node;
|
nsCOMPtr<nsIDOMNode> node;
|
||||||
nsCOMPtr<nsISupports> isupports;
|
nsCOMPtr<nsISupports> isupports;
|
||||||
|
@ -4242,13 +4309,14 @@ nsHTMLEditRules::GetInnerContent(nsIDOMNode *aNode, nsISupportsArray *outArrayOf
|
||||||
nsHTMLEditUtils::IsListItem(node) ) )
|
nsHTMLEditUtils::IsListItem(node) ) )
|
||||||
|| ( aTbl && nsHTMLEditUtils::IsTableElement(node) ) )
|
|| ( aTbl && nsHTMLEditUtils::IsTableElement(node) ) )
|
||||||
{
|
{
|
||||||
res = GetInnerContent(node, outArrayOfNodes, aList, aTbl);
|
res = GetInnerContent(node, outArrayOfNodes, aIndex, aList, aTbl);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
isupports = do_QueryInterface(node);
|
isupports = do_QueryInterface(node);
|
||||||
outArrayOfNodes->AppendElement(isupports);
|
outArrayOfNodes->InsertElementAt(isupports, *aIndex);
|
||||||
|
(*aIndex)++;
|
||||||
}
|
}
|
||||||
nsCOMPtr<nsIDOMNode> tmp;
|
nsCOMPtr<nsIDOMNode> tmp;
|
||||||
res = node->GetNextSibling(getter_AddRefs(tmp));
|
res = node->GetNextSibling(getter_AddRefs(tmp));
|
||||||
|
@ -4820,8 +4888,9 @@ nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
|
||||||
nsCOMPtr<nsIDOMNode> node( do_QueryInterface(isupports) );
|
nsCOMPtr<nsIDOMNode> node( do_QueryInterface(isupports) );
|
||||||
if (nsHTMLEditUtils::IsListItem(node))
|
if (nsHTMLEditUtils::IsListItem(node))
|
||||||
{
|
{
|
||||||
|
PRInt32 j=i;
|
||||||
(*outArrayOfNodes)->RemoveElementAt(i);
|
(*outArrayOfNodes)->RemoveElementAt(i);
|
||||||
res = GetInnerContent(node, *outArrayOfNodes);
|
res = GetInnerContent(node, *outArrayOfNodes, &j);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4839,8 +4908,9 @@ nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
|
||||||
nsCOMPtr<nsIDOMNode> node( do_QueryInterface(isupports) );
|
nsCOMPtr<nsIDOMNode> node( do_QueryInterface(isupports) );
|
||||||
if ( (nsHTMLEditUtils::IsTableElement(node) && !nsHTMLEditUtils::IsTable(node)) )
|
if ( (nsHTMLEditUtils::IsTableElement(node) && !nsHTMLEditUtils::IsTable(node)) )
|
||||||
{
|
{
|
||||||
|
PRInt32 j=i;
|
||||||
(*outArrayOfNodes)->RemoveElementAt(i);
|
(*outArrayOfNodes)->RemoveElementAt(i);
|
||||||
res = GetInnerContent(node, *outArrayOfNodes);
|
res = GetInnerContent(node, *outArrayOfNodes, &j);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4856,8 +4926,9 @@ nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
|
||||||
nsCOMPtr<nsIDOMNode> node( do_QueryInterface(isupports) );
|
nsCOMPtr<nsIDOMNode> node( do_QueryInterface(isupports) );
|
||||||
if (nsHTMLEditUtils::IsDiv(node))
|
if (nsHTMLEditUtils::IsDiv(node))
|
||||||
{
|
{
|
||||||
|
PRInt32 j=i;
|
||||||
(*outArrayOfNodes)->RemoveElementAt(i);
|
(*outArrayOfNodes)->RemoveElementAt(i);
|
||||||
res = GetInnerContent(node, *outArrayOfNodes, PR_FALSE, PR_FALSE);
|
res = GetInnerContent(node, *outArrayOfNodes, &j, PR_FALSE, PR_FALSE);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5029,8 +5100,9 @@ nsHTMLEditRules::GetListActionNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
||||||
if ( (nsHTMLEditUtils::IsTableElement(testNode) && !nsHTMLEditUtils::IsTable(testNode))
|
if ( (nsHTMLEditUtils::IsTableElement(testNode) && !nsHTMLEditUtils::IsTable(testNode))
|
||||||
|| nsHTMLEditUtils::IsDiv(testNode) )
|
|| nsHTMLEditUtils::IsDiv(testNode) )
|
||||||
{
|
{
|
||||||
|
PRInt32 j=i;
|
||||||
(*outArrayOfNodes)->RemoveElementAt(i);
|
(*outArrayOfNodes)->RemoveElementAt(i);
|
||||||
res = GetInnerContent(testNode, *outArrayOfNodes, PR_FALSE);
|
res = GetInnerContent(testNode, *outArrayOfNodes, &j, PR_FALSE);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5087,7 +5159,8 @@ nsHTMLEditRules::LookInsideDivBQandList(nsISupportsArray *aNodeArray)
|
||||||
aNodeArray->RemoveElementAt(0);
|
aNodeArray->RemoveElementAt(0);
|
||||||
if ((nsHTMLEditUtils::IsDiv(curNode) || nsHTMLEditUtils::IsBlockquote(curNode)))
|
if ((nsHTMLEditUtils::IsDiv(curNode) || nsHTMLEditUtils::IsBlockquote(curNode)))
|
||||||
{
|
{
|
||||||
res = GetInnerContent(curNode, aNodeArray, PR_FALSE, PR_FALSE);
|
PRInt32 j=0;
|
||||||
|
res = GetInnerContent(curNode, aNodeArray, &j, PR_FALSE, PR_FALSE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -5158,8 +5231,9 @@ nsHTMLEditRules::GetParagraphFormatNodes(nsCOMPtr<nsISupportsArray> *outArrayOfN
|
||||||
nsHTMLEditUtils::IsList(testNode) ||
|
nsHTMLEditUtils::IsList(testNode) ||
|
||||||
nsHTMLEditUtils::IsListItem(testNode) )
|
nsHTMLEditUtils::IsListItem(testNode) )
|
||||||
{
|
{
|
||||||
|
PRInt32 j=i;
|
||||||
(*outArrayOfNodes)->RemoveElementAt(i);
|
(*outArrayOfNodes)->RemoveElementAt(i);
|
||||||
res = GetInnerContent(testNode, *outArrayOfNodes);
|
res = GetInnerContent(testNode, *outArrayOfNodes, &j);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5517,8 +5591,7 @@ nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection,
|
||||||
// just fall out to default of inserting a BR
|
// just fall out to default of inserting a BR
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
if (nsTextEditUtils::IsBreak(sibling)
|
if (IsVisBreak(sibling) && !nsTextEditUtils::HasMozAttr(sibling))
|
||||||
&& !nsTextEditUtils::HasMozAttr(sibling))
|
|
||||||
{
|
{
|
||||||
PRInt32 newOffset;
|
PRInt32 newOffset;
|
||||||
*aCancel = PR_TRUE;
|
*aCancel = PR_TRUE;
|
||||||
|
@ -5559,8 +5632,7 @@ nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection,
|
||||||
// just fall out to default of inserting a BR
|
// just fall out to default of inserting a BR
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
if (nsTextEditUtils::IsBreak(sibling)
|
if (IsVisBreak(sibling) && !nsTextEditUtils::HasMozAttr(sibling))
|
||||||
&& !nsTextEditUtils::HasMozAttr(sibling))
|
|
||||||
{
|
{
|
||||||
PRInt32 newOffset;
|
PRInt32 newOffset;
|
||||||
*aCancel = PR_TRUE;
|
*aCancel = PR_TRUE;
|
||||||
|
@ -5591,14 +5663,12 @@ nsHTMLEditRules::ReturnInParagraph(nsISelection *aSelection,
|
||||||
nsCOMPtr<nsIDOMNode> nearNode;
|
nsCOMPtr<nsIDOMNode> nearNode;
|
||||||
res = mHTMLEditor->GetPriorHTMLNode(aNode, aOffset, address_of(nearNode));
|
res = mHTMLEditor->GetPriorHTMLNode(aNode, aOffset, address_of(nearNode));
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
if (!nearNode || !nsTextEditUtils::IsBreak(nearNode)
|
if (!nearNode || !IsVisBreak(nearNode) || nsTextEditUtils::HasMozAttr(nearNode))
|
||||||
|| nsTextEditUtils::HasMozAttr(nearNode))
|
|
||||||
{
|
{
|
||||||
// is there a BR after to it?
|
// is there a BR after it?
|
||||||
res = mHTMLEditor->GetNextHTMLNode(aNode, aOffset, address_of(nearNode));
|
res = mHTMLEditor->GetNextHTMLNode(aNode, aOffset, address_of(nearNode));
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
if (!nearNode || !nsTextEditUtils::IsBreak(nearNode)
|
if (!nearNode || !IsVisBreak(nearNode) || nsTextEditUtils::HasMozAttr(nearNode))
|
||||||
|| nsTextEditUtils::HasMozAttr(nearNode))
|
|
||||||
{
|
{
|
||||||
// just fall out to default of inserting a BR
|
// just fall out to default of inserting a BR
|
||||||
return res;
|
return res;
|
||||||
|
@ -5810,7 +5880,7 @@ nsHTMLEditRules::MakeBlockquote(nsISupportsArray *arrayOfNodes)
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// RemoveBlockStyle: make the list nodes have no special block type.
|
// RemoveBlockStyle: make the nodes have no special block type.
|
||||||
//
|
//
|
||||||
nsresult
|
nsresult
|
||||||
nsHTMLEditRules::RemoveBlockStyle(nsISupportsArray *arrayOfNodes)
|
nsHTMLEditRules::RemoveBlockStyle(nsISupportsArray *arrayOfNodes)
|
||||||
|
@ -6473,72 +6543,72 @@ nsHTMLEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection
|
||||||
nsCOMPtr<nsIDOMNode> nearNode;
|
nsCOMPtr<nsIDOMNode> nearNode;
|
||||||
res = mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, address_of(nearNode));
|
res = mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, address_of(nearNode));
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
if (!nearNode) return res;
|
if (nearNode)
|
||||||
|
|
||||||
// is nearNode also a descendant of same block?
|
|
||||||
nsCOMPtr<nsIDOMNode> block, nearBlock;
|
|
||||||
if (IsBlockNode(selNode)) block = selNode;
|
|
||||||
else block = mHTMLEditor->GetBlockNodeParent(selNode);
|
|
||||||
nearBlock = mHTMLEditor->GetBlockNodeParent(nearNode);
|
|
||||||
if (block == nearBlock)
|
|
||||||
{
|
{
|
||||||
if (nearNode && nsTextEditUtils::IsBreak(nearNode)
|
// is nearNode also a descendant of same block?
|
||||||
&& !nsTextEditUtils::IsMozBR(nearNode))
|
nsCOMPtr<nsIDOMNode> block, nearBlock;
|
||||||
{
|
if (IsBlockNode(selNode)) block = selNode;
|
||||||
PRBool bIsLast;
|
else block = mHTMLEditor->GetBlockNodeParent(selNode);
|
||||||
res = mHTMLEditor->IsLastEditableChild(nearNode, &bIsLast);
|
nearBlock = mHTMLEditor->GetBlockNodeParent(nearNode);
|
||||||
if (NS_FAILED(res)) return res;
|
if (block == nearBlock)
|
||||||
if (bIsLast)
|
{
|
||||||
{
|
if (nearNode && nsTextEditUtils::IsBreak(nearNode)
|
||||||
// need to insert special moz BR. Why? Because if we don't
|
&& !nsTextEditUtils::IsMozBR(nearNode))
|
||||||
// the user will see no new line for the break. Also, things
|
{
|
||||||
// like table cells won't grow in height.
|
PRBool bIsLast;
|
||||||
nsCOMPtr<nsIDOMNode> brNode;
|
res = mHTMLEditor->IsLastEditableChild(nearNode, &bIsLast);
|
||||||
res = CreateMozBR(selNode, selOffset, address_of(brNode));
|
if (NS_FAILED(res)) return res;
|
||||||
if (NS_FAILED(res)) return res;
|
if (bIsLast)
|
||||||
res = nsEditor::GetNodeLocation(brNode, address_of(selNode), &selOffset);
|
{
|
||||||
if (NS_FAILED(res)) return res;
|
// need to insert special moz BR. Why? Because if we don't
|
||||||
// selection stays *before* moz-br, sticking to it
|
// the user will see no new line for the break. Also, things
|
||||||
selPriv->SetInterlinePosition(PR_TRUE);
|
// like table cells won't grow in height.
|
||||||
res = aSelection->Collapse(selNode,selOffset);
|
nsCOMPtr<nsIDOMNode> brNode;
|
||||||
if (NS_FAILED(res)) return res;
|
res = CreateMozBR(selNode, selOffset, address_of(brNode));
|
||||||
}
|
if (NS_FAILED(res)) return res;
|
||||||
else
|
res = nsEditor::GetNodeLocation(brNode, address_of(selNode), &selOffset);
|
||||||
{
|
if (NS_FAILED(res)) return res;
|
||||||
// ok, the br inst the last child.
|
// selection stays *before* moz-br, sticking to it
|
||||||
// the br might be right in front of a new block (ie,:
|
selPriv->SetInterlinePosition(PR_TRUE);
|
||||||
// <body> text<br> <ol><li>list item</li></ol></body> )
|
res = aSelection->Collapse(selNode,selOffset);
|
||||||
// in this case we also need moz-br.
|
if (NS_FAILED(res)) return res;
|
||||||
nsCOMPtr<nsIDOMNode> nextNode;
|
}
|
||||||
res = mHTMLEditor->GetNextHTMLNode(nearNode, address_of(nextNode));
|
else
|
||||||
if (NS_FAILED(res)) return res;
|
{
|
||||||
res = mHTMLEditor->GetNextHTMLSibling(nearNode, address_of(nextNode));
|
// ok, the br inst the last child.
|
||||||
if (NS_FAILED(res)) return res;
|
// the br might be right in front of a new block (ie,:
|
||||||
if (nextNode && IsBlockNode(nextNode))
|
// <body> text<br> <ol><li>list item</li></ol></body> )
|
||||||
{
|
// in this case we also need moz-br.
|
||||||
// need to insert special moz BR. Why? Because if we don't
|
nsCOMPtr<nsIDOMNode> nextNode;
|
||||||
// the user will see no new line for the break.
|
res = mHTMLEditor->GetNextHTMLNode(nearNode, address_of(nextNode));
|
||||||
nsCOMPtr<nsIDOMNode> brNode;
|
if (NS_FAILED(res)) return res;
|
||||||
res = CreateMozBR(selNode, selOffset, address_of(brNode));
|
res = mHTMLEditor->GetNextHTMLSibling(nearNode, address_of(nextNode));
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
res = nsEditor::GetNodeLocation(brNode, address_of(selNode), &selOffset);
|
if (nextNode && IsBlockNode(nextNode))
|
||||||
if (NS_FAILED(res)) return res;
|
{
|
||||||
// selection stays *before* moz-br, sticking to it
|
// need to insert special moz BR. Why? Because if we don't
|
||||||
selPriv->SetInterlinePosition(PR_TRUE);
|
// the user will see no new line for the break.
|
||||||
res = aSelection->Collapse(selNode,selOffset);
|
nsCOMPtr<nsIDOMNode> brNode;
|
||||||
if (NS_FAILED(res)) return res;
|
res = CreateMozBR(selNode, selOffset, address_of(brNode));
|
||||||
}
|
if (NS_FAILED(res)) return res;
|
||||||
else if (nextNode && nsTextEditUtils::IsMozBR(nextNode))
|
res = nsEditor::GetNodeLocation(brNode, address_of(selNode), &selOffset);
|
||||||
{
|
if (NS_FAILED(res)) return res;
|
||||||
// selection between br and mozbr. make it stick to mozbr
|
// selection stays *before* moz-br, sticking to it
|
||||||
// so that it will be on blank line.
|
selPriv->SetInterlinePosition(PR_TRUE);
|
||||||
selPriv->SetInterlinePosition(PR_TRUE);
|
res = aSelection->Collapse(selNode,selOffset);
|
||||||
}
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
}
|
||||||
}
|
else if (nextNode && nsTextEditUtils::IsMozBR(nextNode))
|
||||||
|
{
|
||||||
|
// selection between br and mozbr. make it stick to mozbr
|
||||||
|
// so that it will be on blank line.
|
||||||
|
selPriv->SetInterlinePosition(PR_TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// we aren't in a textnode: are we adjacent to a break or an image?
|
// we aren't in a textnode: are we adjacent to a break or an image?
|
||||||
res = mHTMLEditor->GetPriorHTMLSibling(selNode, selOffset, address_of(nearNode));
|
res = mHTMLEditor->GetPriorHTMLSibling(selNode, selOffset, address_of(nearNode));
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
@ -6558,7 +6628,24 @@ nsHTMLEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection
|
||||||
res = FindNearSelectableNode(selNode, selOffset, aAction, address_of(nearNode));
|
res = FindNearSelectableNode(selNode, selOffset, aAction, address_of(nearNode));
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
if (!nearNode) return NS_OK; // couldn't find a near text node
|
if (!nearNode)
|
||||||
|
{
|
||||||
|
// make sure we aren't in an empty block - user will see no cursor. If this
|
||||||
|
// is happening, put a <br> in the block if allowed.
|
||||||
|
nsCOMPtr<nsIDOMNode> block;
|
||||||
|
if (IsBlockNode(selNode)) block = selNode;
|
||||||
|
else block = mHTMLEditor->GetBlockNodeParent(selNode);
|
||||||
|
PRBool bIsEmptyNode;
|
||||||
|
res = mHTMLEditor->IsEmptyNode(block, &bIsEmptyNode, PR_FALSE, PR_FALSE);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
// check if br can go into the destination node
|
||||||
|
if (mHTMLEditor->CanContainTag(selNode, NS_LITERAL_STRING("br")))
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIDOMNode> brNode;
|
||||||
|
res = CreateMozBR(selNode, selOffset, address_of(brNode));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
// is the nearnode a text node?
|
// is the nearnode a text node?
|
||||||
textNode = do_QueryInterface(nearNode);
|
textNode = do_QueryInterface(nearNode);
|
||||||
|
@ -6695,6 +6782,28 @@ nsHTMLEditRules::RemoveEmptyNodes()
|
||||||
nsCOMPtr<nsISupports> isupports;
|
nsCOMPtr<nsISupports> isupports;
|
||||||
PRUint32 nodeCount,j;
|
PRUint32 nodeCount,j;
|
||||||
|
|
||||||
|
// some general notes on the algorithm used here: the goal is to examine all the
|
||||||
|
// nodes in mDocChangeRange, and remove the empty ones. We do this by using a
|
||||||
|
// content iterator to traverse all the nodes in the range, and placing the empty
|
||||||
|
// nodes into an array. After finishing the iteration, we delete the empty nodes
|
||||||
|
// in the array. (they cannot be deleted as we find them becasue that would
|
||||||
|
// invalidate the iterator.)
|
||||||
|
// Since checking to see if a node is empty can be costly for nodes with many
|
||||||
|
// descendants, there are some optimizations made. I rely on the fact that the
|
||||||
|
// iterator is post-order: it will visit children of a node before visiting the
|
||||||
|
// parent node. So if I find that a child node is not empty, I know that it's
|
||||||
|
// parent is not empty without even checking. So I put the parent on a "skipList"
|
||||||
|
// which is just a voidArray of nodes I can skip the empty check on. If I
|
||||||
|
// encounter a node on the skiplist, i skip the processing for that node and replace
|
||||||
|
// it's slot in the skiplist with that node's parent.
|
||||||
|
// An interseting idea is to go ahead and regard parent nodes that are NOT on the
|
||||||
|
// skiplist as being empty (without even doing the IsEmptyNode check) on the theory
|
||||||
|
// that if they weren't empty, we would have encountered a non-empty child earlier
|
||||||
|
// and thus put this parent node on the skiplist.
|
||||||
|
// Unfortunately I can't use that strategy here, because the range may include
|
||||||
|
// some children of a node while excluding others. Thus I could find all the
|
||||||
|
// _examined_ children empty, but still not have an empty parent.
|
||||||
|
|
||||||
// make an isupportsArray to hold a list of nodes
|
// make an isupportsArray to hold a list of nodes
|
||||||
nsresult res = NS_NewISupportsArray(getter_AddRefs(arrayOfNodes));
|
nsresult res = NS_NewISupportsArray(getter_AddRefs(arrayOfNodes));
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
@ -6703,100 +6812,112 @@ nsHTMLEditRules::RemoveEmptyNodes()
|
||||||
iter = do_CreateInstance(kContentIteratorCID);
|
iter = do_CreateInstance(kContentIteratorCID);
|
||||||
if (!iter) return NS_ERROR_NULL_POINTER;
|
if (!iter) return NS_ERROR_NULL_POINTER;
|
||||||
|
|
||||||
// loop over iter and create list of empty containers
|
res = iter->Init(mDocChangeRange);
|
||||||
do
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
nsVoidArray skipList;
|
||||||
|
|
||||||
|
// check for empty nodes
|
||||||
|
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
||||||
{
|
{
|
||||||
res = iter->Init(mDocChangeRange);
|
nsCOMPtr<nsIDOMNode> node, parent;
|
||||||
|
nsCOMPtr<nsIContent> content;
|
||||||
|
res = iter->CurrentNode(getter_AddRefs(content));
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
node = do_QueryInterface(content);
|
||||||
|
if (!node) return NS_ERROR_FAILURE;
|
||||||
|
node->GetParentNode(getter_AddRefs(parent));
|
||||||
|
|
||||||
// gather up a list of empty nodes
|
PRInt32 idx = skipList.IndexOf((void*)node);
|
||||||
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
if (idx>=0)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIDOMNode> node;
|
// this node is on our skip list. Skip processing for this node,
|
||||||
nsCOMPtr<nsIContent> content;
|
// and replace it's value in the skip list with the value of it's parent
|
||||||
res = iter->CurrentNode(getter_AddRefs(content));
|
skipList.ReplaceElementAt((void*)parent, idx);
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
node = do_QueryInterface(content);
|
|
||||||
if (!node) return NS_ERROR_FAILURE;
|
|
||||||
|
|
||||||
PRBool bIsEmptyNode;
|
|
||||||
res = mHTMLEditor->IsEmptyNode(node, &bIsEmptyNode, PR_FALSE, PR_TRUE);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
|
|
||||||
// only consider certain nodes to be empty for purposes of removal
|
|
||||||
if (!(
|
|
||||||
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("a")) ||
|
|
||||||
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("b")) ||
|
|
||||||
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("i")) ||
|
|
||||||
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("u")) ||
|
|
||||||
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("tt")) ||
|
|
||||||
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("s")) ||
|
|
||||||
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("strike")) ||
|
|
||||||
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("big")) ||
|
|
||||||
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("small")) ||
|
|
||||||
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("blink")) ||
|
|
||||||
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("sub")) ||
|
|
||||||
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("sup")) ||
|
|
||||||
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("font")) ||
|
|
||||||
nsHTMLEditUtils::IsList(node) ||
|
|
||||||
nsHTMLEditUtils::IsParagraph(node) ||
|
|
||||||
nsHTMLEditUtils::IsHeader(node) ||
|
|
||||||
nsHTMLEditUtils::IsListItem(node) ||
|
|
||||||
nsHTMLEditUtils::IsBlockquote(node)||
|
|
||||||
nsHTMLEditUtils::IsDiv(node) ||
|
|
||||||
nsHTMLEditUtils::IsPre(node) ||
|
|
||||||
nsHTMLEditUtils::IsAddress(node) ) )
|
|
||||||
{
|
|
||||||
bIsEmptyNode = PR_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bIsEmptyNode && !nsTextEditUtils::IsBody(node))
|
|
||||||
{
|
|
||||||
if (nsHTMLEditUtils::IsParagraph(node) ||
|
|
||||||
nsHTMLEditUtils::IsHeader(node) ||
|
|
||||||
nsHTMLEditUtils::IsListItem(node) ||
|
|
||||||
nsHTMLEditUtils::IsBlockquote(node)||
|
|
||||||
nsHTMLEditUtils::IsPre(node) ||
|
|
||||||
nsHTMLEditUtils::IsAddress(node) )
|
|
||||||
{
|
|
||||||
// if it is one of these, dont delete if sel inside.
|
|
||||||
// this is so we can create empty headings, etc, for the
|
|
||||||
// user to type into.
|
|
||||||
PRBool bIsSelInNode;
|
|
||||||
res = SelectionEndpointInNode(node, &bIsSelInNode);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
if (!bIsSelInNode)
|
|
||||||
{
|
|
||||||
isupports = do_QueryInterface(node);
|
|
||||||
arrayOfNodes->AppendElement(isupports);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// if it's not such an element, delete it even if sel is inside
|
|
||||||
isupports = do_QueryInterface(node);
|
|
||||||
arrayOfNodes->AppendElement(isupports);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res = iter->Next();
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// now delete the empty nodes
|
{
|
||||||
res = arrayOfNodes->Count(&nodeCount);
|
PRBool bIsCandidate = PR_FALSE;
|
||||||
|
PRBool bIsEmptyNode = PR_FALSE;
|
||||||
|
|
||||||
|
// dont delete the body
|
||||||
|
if (!nsTextEditUtils::IsBody(node))
|
||||||
|
{
|
||||||
|
// only consider certain nodes to be empty for purposes of removal
|
||||||
|
if (
|
||||||
|
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("a")) ||
|
||||||
|
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("b")) ||
|
||||||
|
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("i")) ||
|
||||||
|
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("u")) ||
|
||||||
|
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("tt")) ||
|
||||||
|
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("s")) ||
|
||||||
|
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("strike")) ||
|
||||||
|
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("big")) ||
|
||||||
|
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("small")) ||
|
||||||
|
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("blink")) ||
|
||||||
|
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("sub")) ||
|
||||||
|
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("sup")) ||
|
||||||
|
nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("font")) ||
|
||||||
|
nsHTMLEditUtils::IsList(node) ||
|
||||||
|
nsHTMLEditUtils::IsDiv(node) )
|
||||||
|
{
|
||||||
|
bIsCandidate = PR_TRUE;
|
||||||
|
}
|
||||||
|
// these node types are candidates if selection is not in them
|
||||||
|
else if (nsHTMLEditUtils::IsParagraph(node) ||
|
||||||
|
nsHTMLEditUtils::IsHeader(node) ||
|
||||||
|
nsHTMLEditUtils::IsListItem(node) ||
|
||||||
|
nsHTMLEditUtils::IsBlockquote(node)||
|
||||||
|
nsHTMLEditUtils::IsPre(node) ||
|
||||||
|
nsHTMLEditUtils::IsAddress(node) )
|
||||||
|
{
|
||||||
|
// if it is one of these, dont delete if sel inside.
|
||||||
|
// this is so we can create empty headings, etc, for the
|
||||||
|
// user to type into.
|
||||||
|
PRBool bIsSelInNode;
|
||||||
|
res = SelectionEndpointInNode(node, &bIsSelInNode);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
if (!bIsSelInNode)
|
||||||
|
{
|
||||||
|
bIsCandidate = PR_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bIsCandidate)
|
||||||
|
{
|
||||||
|
res = mHTMLEditor->IsEmptyNode(node, &bIsEmptyNode, PR_FALSE, PR_TRUE);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
if (bIsEmptyNode)
|
||||||
|
{
|
||||||
|
isupports = do_QueryInterface(node);
|
||||||
|
if (!isupports) return NS_ERROR_NULL_POINTER;
|
||||||
|
arrayOfNodes->AppendElement(isupports);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bIsEmptyNode)
|
||||||
|
{
|
||||||
|
// put parent on skip list
|
||||||
|
skipList.AppendElement((void*)parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res = iter->Next();
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
for (j = 0; j < nodeCount; j++)
|
}
|
||||||
{
|
|
||||||
isupports = dont_AddRef(arrayOfNodes->ElementAt(0));
|
// now delete the empty nodes
|
||||||
nsCOMPtr<nsIDOMNode> delNode( do_QueryInterface(isupports ) );
|
res = arrayOfNodes->Count(&nodeCount);
|
||||||
arrayOfNodes->RemoveElementAt(0);
|
if (NS_FAILED(res)) return res;
|
||||||
res = mHTMLEditor->DeleteNode(delNode);
|
for (j = 0; j < nodeCount; j++)
|
||||||
if (NS_FAILED(res)) return res;
|
{
|
||||||
}
|
isupports = dont_AddRef(arrayOfNodes->ElementAt(0));
|
||||||
|
nsCOMPtr<nsIDOMNode> delNode( do_QueryInterface(isupports ) );
|
||||||
} while (nodeCount); // if we deleted any, loop again
|
arrayOfNodes->RemoveElementAt(0);
|
||||||
// deleting some nodes may make some parents now empty
|
res = mHTMLEditor->DeleteNode(delNode);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -150,7 +150,7 @@ protected:
|
||||||
nsresult DidMakeBasicBlock(nsISelection *aSelection, nsRulesInfo *aInfo, nsresult aResult);
|
nsresult DidMakeBasicBlock(nsISelection *aSelection, nsRulesInfo *aInfo, nsresult aResult);
|
||||||
nsresult AlignInnerBlocks(nsIDOMNode *aNode, const nsAReadableString *alignType);
|
nsresult AlignInnerBlocks(nsIDOMNode *aNode, const nsAReadableString *alignType);
|
||||||
nsresult AlignBlockContents(nsIDOMNode *aNode, const nsAReadableString *alignType);
|
nsresult AlignBlockContents(nsIDOMNode *aNode, const nsAReadableString *alignType);
|
||||||
nsresult GetInnerContent(nsIDOMNode *aNode, nsISupportsArray *outArrayOfNodes, PRBool aList = PR_TRUE, PRBool aTble = PR_TRUE);
|
nsresult GetInnerContent(nsIDOMNode *aNode, nsISupportsArray *outArrayOfNodes, PRInt32 *aIndex, PRBool aList = PR_TRUE, PRBool aTble = PR_TRUE);
|
||||||
nsCOMPtr<nsIDOMNode> IsInListItem(nsIDOMNode *aNode);
|
nsCOMPtr<nsIDOMNode> IsInListItem(nsIDOMNode *aNode);
|
||||||
nsresult ReturnInHeader(nsISelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset);
|
nsresult ReturnInHeader(nsISelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset);
|
||||||
nsresult ReturnInParagraph(nsISelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset, PRBool *aCancel, PRBool *aHandled);
|
nsresult ReturnInParagraph(nsISelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset, PRBool *aCancel, PRBool *aHandled);
|
||||||
|
|
|
@ -4837,6 +4837,7 @@ nsHTMLEditor::GetLastEditableLeaf( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOut
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// IsEmptyNode: figure out if aNode is an empty node.
|
// IsEmptyNode: figure out if aNode is an empty node.
|
||||||
// A block can have children and still be considered empty,
|
// A block can have children and still be considered empty,
|
||||||
|
@ -4851,6 +4852,7 @@ nsHTMLEditor::IsEmptyNode( nsIDOMNode *aNode,
|
||||||
{
|
{
|
||||||
if (!aNode || !outIsEmptyNode) return NS_ERROR_NULL_POINTER;
|
if (!aNode || !outIsEmptyNode) return NS_ERROR_NULL_POINTER;
|
||||||
*outIsEmptyNode = PR_TRUE;
|
*outIsEmptyNode = PR_TRUE;
|
||||||
|
nsresult res = NS_OK;
|
||||||
|
|
||||||
// effeciency hack - special case if it's a text node
|
// effeciency hack - special case if it's a text node
|
||||||
if (nsEditor::IsTextNode(aNode))
|
if (nsEditor::IsTextNode(aNode))
|
||||||
|
@ -4887,28 +4889,14 @@ nsHTMLEditor::IsEmptyNode( nsIDOMNode *aNode,
|
||||||
PRBool isListItemOrCell =
|
PRBool isListItemOrCell =
|
||||||
nsHTMLEditUtils::IsListItem(aNode) || nsHTMLEditUtils::IsTableCell(aNode);
|
nsHTMLEditUtils::IsListItem(aNode) || nsHTMLEditUtils::IsTableCell(aNode);
|
||||||
|
|
||||||
// iterate over node. if no children, or all children are either
|
// loop over children of node. if no children, or all children are either
|
||||||
// empty text nodes or non-editable, then node qualifies as empty
|
// empty text nodes or non-editable, then node qualifies as empty
|
||||||
nsCOMPtr<nsIContentIterator> iter;
|
nsCOMPtr<nsIDOMNode> child;
|
||||||
nsCOMPtr<nsIContent> nodeAsContent = do_QueryInterface(aNode);
|
aNode->GetFirstChild(getter_AddRefs(child));
|
||||||
if (!nodeAsContent) return NS_ERROR_FAILURE;
|
|
||||||
nsresult res = nsComponentManager::CreateInstance(kCContentIteratorCID,
|
while (child)
|
||||||
nsnull,
|
|
||||||
NS_GET_IID(nsIContentIterator),
|
|
||||||
getter_AddRefs(iter));
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
res = iter->Init(nodeAsContent);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
|
|
||||||
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIDOMNode> node;
|
nsCOMPtr<nsIDOMNode> node = child;
|
||||||
nsCOMPtr<nsIContent> content;
|
|
||||||
res = iter->CurrentNode(getter_AddRefs(content));
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
node = do_QueryInterface(content);
|
|
||||||
if (!node) return NS_ERROR_FAILURE;
|
|
||||||
|
|
||||||
// is the node editable and non-empty? if so, return false
|
// is the node editable and non-empty? if so, return false
|
||||||
if (nsEditor::IsEditable(node))
|
if (nsEditor::IsEditable(node))
|
||||||
{
|
{
|
||||||
|
@ -4936,16 +4924,16 @@ nsHTMLEditor::IsEmptyNode( nsIDOMNode *aNode,
|
||||||
if (isVisible)
|
if (isVisible)
|
||||||
{
|
{
|
||||||
*outIsEmptyNode = PR_FALSE;
|
*outIsEmptyNode = PR_FALSE;
|
||||||
break;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (length)
|
else if (length)
|
||||||
{
|
{
|
||||||
*outIsEmptyNode = PR_FALSE;
|
*outIsEmptyNode = PR_FALSE;
|
||||||
break;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // an editable, non-text node. we aren't an empty block
|
else // an editable, non-text node. we need to check it's content.
|
||||||
{
|
{
|
||||||
// is it the node we are iterating over?
|
// is it the node we are iterating over?
|
||||||
if (node.get() == aNode) break;
|
if (node.get() == aNode) break;
|
||||||
|
@ -4964,14 +4952,14 @@ nsHTMLEditor::IsEmptyNode( nsIDOMNode *aNode,
|
||||||
if (nsHTMLEditUtils::IsList(node) || nsHTMLEditUtils::IsTable(node))
|
if (nsHTMLEditUtils::IsList(node) || nsHTMLEditUtils::IsTable(node))
|
||||||
{
|
{
|
||||||
*outIsEmptyNode = PR_FALSE;
|
*outIsEmptyNode = PR_FALSE;
|
||||||
break;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// is it a form widget?
|
// is it a form widget?
|
||||||
else if (nsHTMLEditUtils::IsFormWidget(aNode))
|
else if (nsHTMLEditUtils::IsFormWidget(aNode))
|
||||||
{
|
{
|
||||||
*outIsEmptyNode = PR_FALSE;
|
*outIsEmptyNode = PR_FALSE;
|
||||||
break;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
PRBool isEmptyNode;
|
PRBool isEmptyNode;
|
||||||
|
@ -4981,13 +4969,12 @@ nsHTMLEditor::IsEmptyNode( nsIDOMNode *aNode,
|
||||||
{
|
{
|
||||||
// otherwise it ain't empty
|
// otherwise it ain't empty
|
||||||
*outIsEmptyNode = PR_FALSE;
|
*outIsEmptyNode = PR_FALSE;
|
||||||
break;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res = iter->Next();
|
node->GetNextSibling(getter_AddRefs(child));
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
|
@ -679,7 +679,8 @@ nsWSRunObject::GetWSNodes()
|
||||||
// block boundary.
|
// block boundary.
|
||||||
nsresult res = NS_OK;
|
nsresult res = NS_OK;
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMNode> blockParent, curStartNode, curEndNode;
|
nsCOMPtr<nsIDOMNode> blockParent;
|
||||||
|
DOMPoint start(mNode, mOffset), end(mNode, mOffset);
|
||||||
if (IsBlockNode(mNode)) blockParent = mNode;
|
if (IsBlockNode(mNode)) blockParent = mNode;
|
||||||
else blockParent = mHTMLEditor->GetBlockNodeParent(mNode);
|
else blockParent = mHTMLEditor->GetBlockNodeParent(mNode);
|
||||||
|
|
||||||
|
@ -718,48 +719,22 @@ nsWSRunObject::GetWSNodes()
|
||||||
mLastNBSPOffset = pos;
|
mLastNBSPOffset = pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
start.SetPoint(mNode,pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!mStartNode)
|
|
||||||
{
|
|
||||||
// we didnt find beginning of whitespace. remember this text node
|
|
||||||
// (and offset 0) as the extent to which we have looked back.
|
|
||||||
curStartNode = mNode;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
PRInt32 curStartOffset=0;
|
|
||||||
nsCOMPtr<nsIDOMNode> priorNode;
|
nsCOMPtr<nsIDOMNode> priorNode;
|
||||||
while (!mStartNode)
|
while (!mStartNode)
|
||||||
{
|
{
|
||||||
// we haven't found the start of ws yet. Keep looking
|
// we haven't found the start of ws yet. Keep looking
|
||||||
|
res = GetPreviousWSNode(start, blockParent, address_of(priorNode));
|
||||||
// do we have a curStartNode? If not, get one.
|
NS_ENSURE_SUCCESS(res, res);
|
||||||
if (!curStartNode)
|
|
||||||
{
|
|
||||||
res = GetPreviousWSNode(mNode, mOffset, blockParent, address_of(curStartNode));
|
|
||||||
NS_ENSURE_SUCCESS(res, res);
|
|
||||||
priorNode = curStartNode;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
res = GetPreviousWSNode(curStartNode, blockParent, address_of(priorNode));
|
|
||||||
NS_ENSURE_SUCCESS(res, res);
|
|
||||||
}
|
|
||||||
if (priorNode)
|
if (priorNode)
|
||||||
{
|
{
|
||||||
if (IsBlockNode(priorNode))
|
if (IsBlockNode(priorNode))
|
||||||
{
|
{
|
||||||
// we encountered a new block. therefore no more ws.
|
start.GetPoint(mStartNode, mStartOffset);
|
||||||
if (mHTMLEditor->IsTextNode(curStartNode))
|
|
||||||
{
|
|
||||||
mStartNode = curStartNode;
|
|
||||||
mStartOffset = curStartOffset;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mHTMLEditor->GetNodeLocation(curStartNode, address_of(mStartNode), &mStartOffset);
|
|
||||||
mStartOffset++;
|
|
||||||
}
|
|
||||||
mStartReason = eOtherBlock;
|
mStartReason = eOtherBlock;
|
||||||
}
|
}
|
||||||
else if (mHTMLEditor->IsTextNode(priorNode))
|
else if (mHTMLEditor->IsTextNode(priorNode))
|
||||||
|
@ -796,71 +771,28 @@ nsWSRunObject::GetWSNodes()
|
||||||
mLastNBSPOffset = pos;
|
mLastNBSPOffset = pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
start.SetPoint(priorNode,pos);
|
||||||
}
|
}
|
||||||
if (!mStartNode)
|
|
||||||
{
|
|
||||||
// we didnt find beginning of whitespace. remember this text node
|
|
||||||
// (and offset 0) as the extent to which we have looked back.
|
|
||||||
curStartNode = priorNode;
|
|
||||||
curStartOffset = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (nsTextEditUtils::IsBreak(priorNode))
|
|
||||||
{
|
|
||||||
// we encountered a break. therefore no more ws.
|
|
||||||
if (mHTMLEditor->IsTextNode(curStartNode))
|
|
||||||
{
|
|
||||||
mStartNode = curStartNode;
|
|
||||||
mStartOffset = curStartOffset;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mHTMLEditor->GetNodeLocation(curStartNode, address_of(mStartNode), &mStartOffset);
|
|
||||||
mStartOffset++;
|
|
||||||
}
|
|
||||||
mStartReason = eBreak;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// it's a special node, like <img>, that is not a block and not
|
// it's a break or a special node, like <img>, that is not a block and not
|
||||||
// a break but still serves as a terminator to ws runs.
|
// a break but still serves as a terminator to ws runs.
|
||||||
if (mHTMLEditor->IsTextNode(curStartNode))
|
start.GetPoint(mStartNode, mStartOffset);
|
||||||
{
|
if (nsTextEditUtils::IsBreak(priorNode))
|
||||||
mStartNode = curStartNode;
|
mStartReason = eBreak;
|
||||||
mStartOffset = curStartOffset;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
mStartReason = eSpecial;
|
||||||
mHTMLEditor->GetNodeLocation(curStartNode, address_of(mStartNode), &mStartOffset);
|
|
||||||
mStartOffset++;
|
|
||||||
}
|
|
||||||
mStartReason = eSpecial;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// no prior node means we exhausted blockParent
|
// no prior node means we exhausted blockParent
|
||||||
if (!curStartNode)
|
start.GetPoint(mStartNode, mStartOffset);
|
||||||
{
|
|
||||||
// we never found anything to work with, so start
|
|
||||||
// is at beginning of block parent
|
|
||||||
mStartNode = blockParent;
|
|
||||||
mStartOffset = 0;
|
|
||||||
}
|
|
||||||
else if (mHTMLEditor->IsTextNode(curStartNode))
|
|
||||||
{
|
|
||||||
mStartNode = curStartNode;
|
|
||||||
mStartOffset = curStartOffset;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mHTMLEditor->GetNodeLocation(curStartNode, address_of(mStartNode), &mStartOffset);
|
|
||||||
mStartOffset++;
|
|
||||||
}
|
|
||||||
mStartReason = eThisBlock;
|
mStartReason = eThisBlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PRInt32 curEndOffset=0;
|
|
||||||
// then look ahead to find following ws nodes
|
// then look ahead to find following ws nodes
|
||||||
if (mHTMLEditor->IsTextNode(mNode))
|
if (mHTMLEditor->IsTextNode(mNode))
|
||||||
{
|
{
|
||||||
|
@ -896,48 +828,23 @@ nsWSRunObject::GetWSNodes()
|
||||||
mFirstNBSPOffset = pos;
|
mFirstNBSPOffset = pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
end.SetPoint(mNode,pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!mEndNode)
|
|
||||||
{
|
|
||||||
// we didnt find end of whitespace. remember this text node
|
|
||||||
// (and offset len) as the extent to which we have looked ahead.
|
|
||||||
curEndNode = mNode;
|
|
||||||
curEndOffset = len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMNode> nextNode;
|
nsCOMPtr<nsIDOMNode> nextNode;
|
||||||
while (!mEndNode)
|
while (!mEndNode)
|
||||||
{
|
{
|
||||||
// we haven't found the end of ws yet. Keep looking
|
// we haven't found the end of ws yet. Keep looking
|
||||||
|
res = GetNextWSNode(end, blockParent, address_of(nextNode));
|
||||||
// do we have a curEndNode? If not, get one.
|
NS_ENSURE_SUCCESS(res, res);
|
||||||
if (!curEndNode)
|
|
||||||
{
|
|
||||||
res = GetNextWSNode(mNode, mOffset, blockParent, address_of(curEndNode));
|
|
||||||
NS_ENSURE_SUCCESS(res, res);
|
|
||||||
nextNode = curEndNode;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
res = GetNextWSNode(curEndNode, blockParent, address_of(nextNode));
|
|
||||||
NS_ENSURE_SUCCESS(res, res);
|
|
||||||
}
|
|
||||||
if (nextNode)
|
if (nextNode)
|
||||||
{
|
{
|
||||||
if (IsBlockNode(nextNode))
|
if (IsBlockNode(nextNode))
|
||||||
{
|
{
|
||||||
// we encountered a new block. therefore no more ws.
|
// we encountered a new block. therefore no more ws.
|
||||||
if (mHTMLEditor->IsTextNode(curEndNode))
|
end.GetPoint(mEndNode, mEndOffset);
|
||||||
{
|
|
||||||
mEndNode = curEndNode;
|
|
||||||
mEndOffset = curEndOffset;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mHTMLEditor->GetNodeLocation(curEndNode, address_of(mEndNode), &mEndOffset);
|
|
||||||
}
|
|
||||||
mEndReason = eOtherBlock;
|
mEndReason = eOtherBlock;
|
||||||
}
|
}
|
||||||
else if (mHTMLEditor->IsTextNode(nextNode))
|
else if (mHTMLEditor->IsTextNode(nextNode))
|
||||||
|
@ -975,66 +882,25 @@ nsWSRunObject::GetWSNodes()
|
||||||
mFirstNBSPOffset = pos;
|
mFirstNBSPOffset = pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
end.SetPoint(nextNode,pos+1);
|
||||||
}
|
}
|
||||||
if (!mEndNode)
|
|
||||||
{
|
|
||||||
// we didnt find end of whitespace. remember this text node
|
|
||||||
// (and offset len) as the extent to which we have looked ahead.
|
|
||||||
curEndNode = nextNode;
|
|
||||||
curEndOffset = len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (nsTextEditUtils::IsBreak(nextNode))
|
|
||||||
{
|
|
||||||
// we encountered a break. therefore no more ws.
|
|
||||||
if (mHTMLEditor->IsTextNode(curEndNode))
|
|
||||||
{
|
|
||||||
mEndNode = curEndNode;
|
|
||||||
mEndOffset = curEndOffset;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mHTMLEditor->GetNodeLocation(curEndNode, address_of(mEndNode), &mEndOffset);
|
|
||||||
}
|
|
||||||
mEndReason = eBreak;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// it's a special node, like <img>, that is not a block and not
|
// we encountered a break or a special node, like <img>,
|
||||||
// a break but still serves as a terminator to ws runs.
|
// that is not a block and not a break but still
|
||||||
if (mHTMLEditor->IsTextNode(curEndNode))
|
// serves as a terminator to ws runs.
|
||||||
{
|
end.GetPoint(mEndNode, mEndOffset);
|
||||||
mEndNode = curEndNode;
|
if (nsTextEditUtils::IsBreak(nextNode))
|
||||||
mEndOffset = curEndOffset;
|
mStartReason = eBreak;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
mStartReason = eSpecial;
|
||||||
mHTMLEditor->GetNodeLocation(curEndNode, address_of(mEndNode), &mEndOffset);
|
|
||||||
}
|
|
||||||
mEndReason = eSpecial;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// no next node means we exhausted blockParent
|
// no next node means we exhausted blockParent
|
||||||
if (!curEndNode)
|
end.GetPoint(mEndNode, mEndOffset);
|
||||||
{
|
|
||||||
// we never found anything to work with, so end
|
|
||||||
// is at end of block parent
|
|
||||||
mEndNode = blockParent;
|
|
||||||
PRUint32 count;
|
|
||||||
mHTMLEditor->GetLengthOfDOMNode(blockParent, count);
|
|
||||||
mEndOffset = count;
|
|
||||||
}
|
|
||||||
else if (mHTMLEditor->IsTextNode(curEndNode))
|
|
||||||
{
|
|
||||||
mEndNode = curEndNode;
|
|
||||||
mEndOffset = curEndOffset;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mHTMLEditor->GetNodeLocation(curEndNode, address_of(mEndNode), &mEndOffset);
|
|
||||||
}
|
|
||||||
mEndReason = eThisBlock;
|
mEndReason = eThisBlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1272,51 +1138,16 @@ nsWSRunObject::GetPreviousWSNode(nsIDOMNode *aStartNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsWSRunObject::GetNextWSNode(nsIDOMNode *aStartNode,
|
nsWSRunObject::GetPreviousWSNode(DOMPoint aPoint,
|
||||||
nsIDOMNode *aBlockParent,
|
nsIDOMNode *aBlockParent,
|
||||||
nsCOMPtr<nsIDOMNode> *aNextNode)
|
nsCOMPtr<nsIDOMNode> *aPriorNode)
|
||||||
{
|
{
|
||||||
// can't really recycle various getnext/prior routines because we have special needs
|
nsCOMPtr<nsIDOMNode> node;
|
||||||
// here. Need to step into inline containers but not block containers.
|
PRInt32 offset;
|
||||||
if (!aStartNode || !aBlockParent || !aNextNode) return NS_ERROR_NULL_POINTER;
|
aPoint.GetPoint(node, offset);
|
||||||
|
return GetPreviousWSNode(node,offset,aBlockParent,aPriorNode);
|
||||||
*aNextNode = 0;
|
|
||||||
nsresult res = aStartNode->GetNextSibling(getter_AddRefs(*aNextNode));
|
|
||||||
NS_ENSURE_SUCCESS(res, res);
|
|
||||||
nsCOMPtr<nsIDOMNode> temp, curNode = aStartNode;
|
|
||||||
while (!*aNextNode)
|
|
||||||
{
|
|
||||||
// we have exhausted nodes in parent of aStartNode.
|
|
||||||
res = curNode->GetParentNode(getter_AddRefs(temp));
|
|
||||||
NS_ENSURE_SUCCESS(res, res);
|
|
||||||
if (!temp) return NS_ERROR_NULL_POINTER;
|
|
||||||
if (temp == aBlockParent)
|
|
||||||
{
|
|
||||||
// we have exhausted nodes in the block parent. The convention here is to return null.
|
|
||||||
*aNextNode = nsnull;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
// we have a parent: look for next sibling
|
|
||||||
res = temp->GetNextSibling(getter_AddRefs(*aNextNode));
|
|
||||||
NS_ENSURE_SUCCESS(res, res);
|
|
||||||
curNode = temp;
|
|
||||||
}
|
|
||||||
// we have a next node. If it's a block, return it.
|
|
||||||
if (IsBlockNode(*aNextNode))
|
|
||||||
return NS_OK;
|
|
||||||
// else if it's a container, get deep leftmost child
|
|
||||||
else if (mHTMLEditor->IsContainer(*aNextNode))
|
|
||||||
{
|
|
||||||
temp = mHTMLEditor->GetLeftmostChild(*aNextNode);
|
|
||||||
if (temp)
|
|
||||||
*aNextNode = temp;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
// else return the node itself
|
|
||||||
return NS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsWSRunObject::GetPreviousWSNode(nsIDOMNode *aStartNode,
|
nsWSRunObject::GetPreviousWSNode(nsIDOMNode *aStartNode,
|
||||||
PRInt16 aOffset,
|
PRInt16 aOffset,
|
||||||
|
@ -1369,6 +1200,62 @@ nsWSRunObject::GetPreviousWSNode(nsIDOMNode *aStartNode,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsWSRunObject::GetNextWSNode(nsIDOMNode *aStartNode,
|
||||||
|
nsIDOMNode *aBlockParent,
|
||||||
|
nsCOMPtr<nsIDOMNode> *aNextNode)
|
||||||
|
{
|
||||||
|
// can't really recycle various getnext/prior routines because we have special needs
|
||||||
|
// here. Need to step into inline containers but not block containers.
|
||||||
|
if (!aStartNode || !aBlockParent || !aNextNode) return NS_ERROR_NULL_POINTER;
|
||||||
|
|
||||||
|
*aNextNode = 0;
|
||||||
|
nsresult res = aStartNode->GetNextSibling(getter_AddRefs(*aNextNode));
|
||||||
|
NS_ENSURE_SUCCESS(res, res);
|
||||||
|
nsCOMPtr<nsIDOMNode> temp, curNode = aStartNode;
|
||||||
|
while (!*aNextNode)
|
||||||
|
{
|
||||||
|
// we have exhausted nodes in parent of aStartNode.
|
||||||
|
res = curNode->GetParentNode(getter_AddRefs(temp));
|
||||||
|
NS_ENSURE_SUCCESS(res, res);
|
||||||
|
if (!temp) return NS_ERROR_NULL_POINTER;
|
||||||
|
if (temp == aBlockParent)
|
||||||
|
{
|
||||||
|
// we have exhausted nodes in the block parent. The convention here is to return null.
|
||||||
|
*aNextNode = nsnull;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
// we have a parent: look for next sibling
|
||||||
|
res = temp->GetNextSibling(getter_AddRefs(*aNextNode));
|
||||||
|
NS_ENSURE_SUCCESS(res, res);
|
||||||
|
curNode = temp;
|
||||||
|
}
|
||||||
|
// we have a next node. If it's a block, return it.
|
||||||
|
if (IsBlockNode(*aNextNode))
|
||||||
|
return NS_OK;
|
||||||
|
// else if it's a container, get deep leftmost child
|
||||||
|
else if (mHTMLEditor->IsContainer(*aNextNode))
|
||||||
|
{
|
||||||
|
temp = mHTMLEditor->GetLeftmostChild(*aNextNode);
|
||||||
|
if (temp)
|
||||||
|
*aNextNode = temp;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
// else return the node itself
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsWSRunObject::GetNextWSNode(DOMPoint aPoint,
|
||||||
|
nsIDOMNode *aBlockParent,
|
||||||
|
nsCOMPtr<nsIDOMNode> *aNextNode)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIDOMNode> node;
|
||||||
|
PRInt32 offset;
|
||||||
|
aPoint.GetPoint(node, offset);
|
||||||
|
return GetNextWSNode(node,offset,aBlockParent,aNextNode);
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsWSRunObject::GetNextWSNode(nsIDOMNode *aStartNode,
|
nsWSRunObject::GetNextWSNode(nsIDOMNode *aStartNode,
|
||||||
PRInt16 aOffset,
|
PRInt16 aOffset,
|
||||||
|
|
|
@ -239,6 +239,27 @@ class nsWSRunObject
|
||||||
WSPoint(nsITextContent *aTextNode, PRInt32 aOffset, PRUnichar aChar) :
|
WSPoint(nsITextContent *aTextNode, PRInt32 aOffset, PRUnichar aChar) :
|
||||||
mTextNode(aTextNode),mOffset(aOffset),mChar(aChar) {}
|
mTextNode(aTextNode),mOffset(aOffset),mChar(aChar) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// general dom point utility struct
|
||||||
|
struct DOMPoint
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIDOMNode> node;
|
||||||
|
PRInt32 offset;
|
||||||
|
|
||||||
|
DOMPoint() : node(0),offset(0) {}
|
||||||
|
DOMPoint(nsIDOMNode *aNode, PRInt32 aOffset) :
|
||||||
|
node(aNode),offset(aOffset) {}
|
||||||
|
void SetPoint(nsIDOMNode *aNode, PRInt32 aOffset)
|
||||||
|
{
|
||||||
|
node = aNode; offset = aOffset;
|
||||||
|
}
|
||||||
|
void GetPoint(nsCOMPtr<nsIDOMNode> &aNode, PRInt32 &aOffset)
|
||||||
|
{
|
||||||
|
aNode = node; aOffset = offset;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// protected methods ---------------------------------------------------------
|
// protected methods ---------------------------------------------------------
|
||||||
// tons of utility methods.
|
// tons of utility methods.
|
||||||
|
@ -251,17 +272,23 @@ class nsWSRunObject
|
||||||
nsresult GetPreviousWSNode(nsIDOMNode *aStartNode,
|
nsresult GetPreviousWSNode(nsIDOMNode *aStartNode,
|
||||||
nsIDOMNode *aBlockParent,
|
nsIDOMNode *aBlockParent,
|
||||||
nsCOMPtr<nsIDOMNode> *aPriorNode);
|
nsCOMPtr<nsIDOMNode> *aPriorNode);
|
||||||
nsresult GetNextWSNode(nsIDOMNode *aStartNode,
|
|
||||||
nsIDOMNode *aBlockParent,
|
|
||||||
nsCOMPtr<nsIDOMNode> *aNextNode);
|
|
||||||
nsresult GetPreviousWSNode(nsIDOMNode *aStartNode,
|
nsresult GetPreviousWSNode(nsIDOMNode *aStartNode,
|
||||||
PRInt16 aOffset,
|
PRInt16 aOffset,
|
||||||
nsIDOMNode *aBlockParent,
|
nsIDOMNode *aBlockParent,
|
||||||
nsCOMPtr<nsIDOMNode> *aPriorNode);
|
nsCOMPtr<nsIDOMNode> *aPriorNode);
|
||||||
|
nsresult GetPreviousWSNode(DOMPoint aPoint,
|
||||||
|
nsIDOMNode *aBlockParent,
|
||||||
|
nsCOMPtr<nsIDOMNode> *aPriorNode);
|
||||||
|
nsresult GetNextWSNode(nsIDOMNode *aStartNode,
|
||||||
|
nsIDOMNode *aBlockParent,
|
||||||
|
nsCOMPtr<nsIDOMNode> *aNextNode);
|
||||||
nsresult GetNextWSNode(nsIDOMNode *aStartNode,
|
nsresult GetNextWSNode(nsIDOMNode *aStartNode,
|
||||||
PRInt16 aOffset,
|
PRInt16 aOffset,
|
||||||
nsIDOMNode *aBlockParent,
|
nsIDOMNode *aBlockParent,
|
||||||
nsCOMPtr<nsIDOMNode> *aNextNode);
|
nsCOMPtr<nsIDOMNode> *aNextNode);
|
||||||
|
nsresult GetNextWSNode(DOMPoint aPoint,
|
||||||
|
nsIDOMNode *aBlockParent,
|
||||||
|
nsCOMPtr<nsIDOMNode> *aNextNode);
|
||||||
nsresult PrepareToDeleteRangePriv(nsWSRunObject* aEndObject);
|
nsresult PrepareToDeleteRangePriv(nsWSRunObject* aEndObject);
|
||||||
nsresult PrepareToSplitAcrossBlocksPriv();
|
nsresult PrepareToSplitAcrossBlocksPriv();
|
||||||
nsresult DeleteChars(nsIDOMNode *aStartNode, PRInt32 aStartOffset,
|
nsresult DeleteChars(nsIDOMNode *aStartNode, PRInt32 aStartOffset,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче