some cleanup and also selection enforcement for plaintext documents: selection is pinned to within the PRE tag on any edit action

This commit is contained in:
jfrancis%netscape.com 1999-07-01 13:42:03 +00:00
Родитель f83c611c20
Коммит c491832078
10 изменённых файлов: 839 добавлений и 841 удалений

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

@ -60,6 +60,7 @@ enum
nsHTMLEditRules::nsHTMLEditRules()
{
mPINSelection = PR_FALSE;
}
nsHTMLEditRules::~nsHTMLEditRules()
@ -452,85 +453,27 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
*aCancel = PR_TRUE;
nsAutoSelectionReset selectionResetter(aSelection);
nsresult res = NS_OK;
nsresult res;
// get selection range - XXX generalize to collection of ranges
// gather up factoids about the range
nsCOMPtr<nsIDOMRange> selectionRange;
nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIDOMNode> endNode;
nsCOMPtr<nsIDOMNode> commonParent;
PRInt32 startOffset, endOffset;
// convert the selection ranges into "promoted" selection ranges:
// this basically just expands the range to include the immediate
// block parent, and then further expands to include any ancestors
// whose children are all in the range
res = aSelection->GetRangeAt(0,getter_AddRefs(selectionRange));
nsCOMPtr<nsISupportsArray> arrayOfRanges;
res = GetPromotedRanges(aSelection, &arrayOfRanges, kMakeList);
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartParent(getter_AddRefs(startNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartOffset(&startOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndParent(getter_AddRefs(endNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndOffset(&endOffset);
if (NS_FAILED(res)) return res;
// res = selectionRange->GetCommonParent(getter_AddRefs(commonParent));
// if (NS_FAILED(res)) return res;
// make a new adjusted range to represent the appropriate block content
// this is tricky. the basic idea is to push out the range endpoints
// to truly enclose the blocks that we will affect
nsCOMPtr<nsIDOMNode> listStartNode;
nsCOMPtr<nsIDOMNode> listEndNode;
PRInt32 listStartOffset, listEndOffset;
nsCOMPtr<nsIDOMRange> opRange;
res = GetPromotedPoint( kStart, startNode, startOffset, kMakeList, &listStartNode, &listStartOffset);
if (NS_FAILED(res)) return res;
res = GetPromotedPoint( kEnd, endNode, endOffset, kMakeList, &listEndNode, &listEndOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->Clone(getter_AddRefs(opRange));
if (NS_FAILED(res)) return res;
opRange->SetStart(listStartNode, listStartOffset);
if (NS_FAILED(res)) return res;
opRange->SetEnd(listEndNode, listEndOffset);
if (NS_FAILED(res)) return res;
// use subtree iterator to boogie over the snazzy new range
// we wil gather the top level nodes to process into a list
nsCOMPtr<nsIContentIterator> iter;
res = nsComponentManager::CreateInstance(kSubtreeIteratorCID,
nsnull,
nsIContentIterator::GetIID(),
getter_AddRefs(iter));
if (NS_FAILED(res)) return res;
res = iter->Init(opRange);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsISupportsArray> list;
res = NS_NewISupportsArray(getter_AddRefs(list));
while (NS_COMFALSE == iter->IsDone())
{
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIContent> content;
res = iter->CurrentNode(getter_AddRefs(content));
node = do_QueryInterface(content);
if ((NS_SUCCEEDED(res)) && node)
{
// can't manipulate tree while using subtree iterator, or we will
// confuse it's little mind
// instead chuck the results into an array.
list->AppendElement(node);
}
res = iter->Next();
if (NS_FAILED(res)) return res;
}
// use these ranges to contruct a list of nodes to act on.
nsCOMPtr<nsISupportsArray> arrayOfNodes;
res = GetNodesForOperation(arrayOfRanges, &arrayOfNodes, kMakeList);
if (NS_FAILED(res)) return res;
// if we ended up with any nodes in the list that aren't blocknodes,
// find their block parent instead and use that.
// i started writing this and then the sky fell. there are big questions
// about what to do here. i may need to switch rom think about an array of
// about what to do here. i may need to switch from thinking about an array of
// nodes to act on to instead think of an array of ranges to act on.
// Next we remove all the <br>'s in the array. This won't prevent <br>'s
@ -541,28 +484,28 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
PRUint32 listCount;
PRInt32 i;
list->Count(&listCount);
arrayOfNodes->Count(&listCount);
for (i=listCount-1; i>=0; i--)
{
nsISupports *thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> testNode( do_QueryInterface(thingy) );
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
nsCOMPtr<nsIDOMNode> testNode( do_QueryInterface(isupports ) );
if (IsBreak(testNode))
{
list->RemoveElementAt(i);
arrayOfNodes->RemoveElementAt(i);
}
else if (!nsEditor::IsEditable(testNode))
{
list->RemoveElementAt(i);
arrayOfNodes->RemoveElementAt(i);
}
}
// if there is only one node in the array, and it is a list, div, or blockquote,
// then look inside of it until we find what we want to make a list out of.
arrayOfNodes->Count(&listCount);
if (listCount == 1)
{
nsISupports *thingy;
thingy = list->ElementAt(0);
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(thingy) );
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
while (IsDiv(curNode) || IsOrderedList(curNode) || IsUnorderedList(curNode) || IsBlockquote(curNode))
{
@ -575,57 +518,40 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
{
// keep diving
nsCOMPtr <nsIDOMNode> tmpNode = nsEditor::GetChildAt(curNode, 0);
// check editablility XXX moose
curNode = tmpNode;
}
else
{
// stop diving
break;
if (IsDiv(tmpNode) || IsOrderedList(tmpNode) || IsUnorderedList(tmpNode) || IsBlockquote(tmpNode))
{
// check editablility XXX moose
curNode = tmpNode;
}
else break;
}
else break;
}
// we've found innermost list/blockquote/div:
// replace the one node in the array with this node
list->ReplaceElementAt(curNode, 0);
isupports = do_QueryInterface(curNode);
arrayOfNodes->ReplaceElementAt(isupports, 0);
}
// Next we detect all the transitions in the array, where a transition
// means that adjacent nodes in the array don't have the same parent.
list->Count(&listCount);
nsVoidArray transitionList;
nsCOMPtr<nsIDOMNode> prevElementParent;
nsCOMPtr<nsIDOMNode> curElementParent;
for (i=0; i<listCount; i++)
{
nsISupports *thingy;
thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> transNode( do_QueryInterface(thingy) );
transNode->GetParentNode(getter_AddRefs(curElementParent));
if (curElementParent != prevElementParent)
{
transitionList.InsertElementAt((void*)PR_TRUE,i); // different parents: transition point
}
else
{
transitionList.InsertElementAt((void*)PR_FALSE,i); // same parents: these nodes grew up together
}
prevElementParent = curElementParent;
}
res = MakeTransitionList(arrayOfNodes, &transitionList);
if (NS_FAILED(res)) return res;
// Ok, now go through all the nodes and put then in the list,
// or whatever is approriate. Wohoo!
arrayOfNodes->Count(&listCount);
nsCOMPtr<nsIDOMNode> curParent;
nsCOMPtr<nsIDOMNode> curList;
for (i=0; i<listCount; i++)
{
// here's where we actually figure out what to do
nsISupports *thingy;
thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(thingy) );
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
PRInt32 offset;
res = nsEditor::GetNodeLocation(curNode, &curParent, &offset);
if (NS_FAILED(res)) return res;
@ -730,116 +656,42 @@ nsHTMLEditRules::WillIndent(nsIDOMSelection *aSelection, PRBool *aCancel)
*aCancel = PR_TRUE;
nsAutoSelectionReset selectionResetter(aSelection);
nsresult res = NS_OK;
nsresult res;
// get selection range - XXX generalize to collection of ranges
// gather up factoids about the range
nsCOMPtr<nsIDOMRange> selectionRange;
nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIDOMNode> endNode;
PRInt32 startOffset, endOffset;
// convert the selection ranges into "promoted" selection ranges:
// this basically just expands the range to include the immediate
// block parent, and then further expands to include any ancestors
// whose children are all in the range
res = aSelection->GetRangeAt(0,getter_AddRefs(selectionRange));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartParent(getter_AddRefs(startNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartOffset(&startOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndParent(getter_AddRefs(endNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndOffset(&endOffset);
nsCOMPtr<nsISupportsArray> arrayOfRanges;
res = GetPromotedRanges(aSelection, &arrayOfRanges, kIndent);
if (NS_FAILED(res)) return res;
// make a new adjusted range to represent the appropriate block content
// this is tricky. the basic idea is to push out the range endpoints
// to truly enclose the blocks that we will affect
nsCOMPtr<nsIDOMNode> quoteStartNode;
nsCOMPtr<nsIDOMNode> quoteEndNode;
PRInt32 quoteStartOffset, quoteEndOffset;
nsCOMPtr<nsIDOMRange> opRange;
res = GetPromotedPoint( kStart, startNode, startOffset, kIndent, &quoteStartNode, &quoteStartOffset);
if (NS_FAILED(res)) return res;
res = GetPromotedPoint( kEnd, endNode, endOffset, kIndent, &quoteEndNode, &quoteEndOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->Clone(getter_AddRefs(opRange));
if (NS_FAILED(res)) return res;
opRange->SetStart(quoteStartNode, quoteStartOffset);
if (NS_FAILED(res)) return res;
opRange->SetEnd(quoteEndNode, quoteEndOffset);
if (NS_FAILED(res)) return res;
// use subtree iterator to boogie over the snazzy new range
// we wil gather the top level nodes to process into an array
nsCOMPtr<nsIContentIterator> iter;
res = nsComponentManager::CreateInstance(kSubtreeIteratorCID,
nsnull,
nsIContentIterator::GetIID(),
getter_AddRefs(iter));
if (NS_FAILED(res)) return res;
res = iter->Init(opRange);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsISupportsArray> list;
res = NS_NewISupportsArray(getter_AddRefs(list));
while (NS_COMFALSE == iter->IsDone())
{
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIContent> content;
res = iter->CurrentNode(getter_AddRefs(content));
node = do_QueryInterface(content);
if ((NS_SUCCEEDED(res)) && node)
{
// can't manipulate tree while using subtree iterator, or we will
// confuse it's little mind
// instead chuck the results into an array.
list->AppendElement(node);
}
res = iter->Next();
if (NS_FAILED(res)) return res;
}
// use these ranges to contruct a list of nodes to act on.
nsCOMPtr<nsISupportsArray> arrayOfNodes;
res = GetNodesForOperation(arrayOfRanges, &arrayOfNodes, kIndent);
if (NS_FAILED(res)) return res;
// Next we detect all the transitions in the array, where a transition
// means that adjacent nodes in the array don't have the same parent.
nsVoidArray transitionList;
res = MakeTransitionList(arrayOfNodes, &transitionList);
if (NS_FAILED(res)) return res;
// Ok, now go through all the nodes and put them in a blockquote,
// or whatever is appropriate. Wohoo!
PRUint32 listCount;
PRInt32 i;
list->Count(&listCount);
nsVoidArray transitionList;
nsCOMPtr<nsIDOMNode> prevElementParent;
nsCOMPtr<nsIDOMNode> curElementParent;
for (i=0; i<listCount; i++)
{
nsISupports *thingy;
thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> transNode( do_QueryInterface(thingy) );
transNode->GetParentNode(getter_AddRefs(curElementParent));
if (curElementParent != prevElementParent)
{
transitionList.InsertElementAt((void*)PR_TRUE,i); // different parents: transition point
}
else
{
transitionList.InsertElementAt((void*)PR_FALSE,i); // same parents: these nodes grew up together
}
prevElementParent = curElementParent;
}
// Ok, now go through all the lodes and put them in a blockquote,
// or whatever is appropriate. Wohoo!
arrayOfNodes->Count(&listCount);
nsCOMPtr<nsIDOMNode> curParent;
nsCOMPtr<nsIDOMNode> curQuote;
for (i=0; i<listCount; i++)
{
// here's where we actually figure out what to do
nsISupports *thingy;
thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(thingy) );
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
PRInt32 offset;
res = nsEditor::GetNodeLocation(curNode, &curParent, &offset);
if (NS_FAILED(res)) return res;
@ -878,113 +730,39 @@ nsHTMLEditRules::WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel)
nsAutoSelectionReset selectionResetter(aSelection);
nsresult res = NS_OK;
// get selection range - XXX generalize to collection of ranges
// gather up factoids about the range
nsCOMPtr<nsIDOMRange> selectionRange;
nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIDOMNode> endNode;
PRInt32 startOffset, endOffset;
// convert the selection ranges into "promoted" selection ranges:
// this basically just expands the range to include the immediate
// block parent, and then further expands to include any ancestors
// whose children are all in the range
res = aSelection->GetRangeAt(0,getter_AddRefs(selectionRange));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartParent(getter_AddRefs(startNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartOffset(&startOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndParent(getter_AddRefs(endNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndOffset(&endOffset);
nsCOMPtr<nsISupportsArray> arrayOfRanges;
res = GetPromotedRanges(aSelection, &arrayOfRanges, kOutdent);
if (NS_FAILED(res)) return res;
// make a new adjusted range to represent the appropriate block content
// this is tricky. the basic idea is to push out the range endpoints
// to truly enclose the blocks that we will affect
nsCOMPtr<nsIDOMNode> quoteStartNode;
nsCOMPtr<nsIDOMNode> quoteEndNode;
PRInt32 quoteStartOffset, quoteEndOffset;
nsCOMPtr<nsIDOMRange> opRange;
res = GetPromotedPoint( kStart, startNode, startOffset, kIndent, &quoteStartNode, &quoteStartOffset);
if (NS_FAILED(res)) return res;
res = GetPromotedPoint( kEnd, endNode, endOffset, kIndent, &quoteEndNode, &quoteEndOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->Clone(getter_AddRefs(opRange));
if (NS_FAILED(res)) return res;
opRange->SetStart(quoteStartNode, quoteStartOffset);
if (NS_FAILED(res)) return res;
opRange->SetEnd(quoteEndNode, quoteEndOffset);
if (NS_FAILED(res)) return res;
// use subtree iterator to boogie over the snazzy new range
// we wil gather the top level nodes to process into an array
nsCOMPtr<nsIContentIterator> iter;
res = nsComponentManager::CreateInstance(kSubtreeIteratorCID,
nsnull,
nsIContentIterator::GetIID(),
getter_AddRefs(iter));
if (NS_FAILED(res)) return res;
res = iter->Init(opRange);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsISupportsArray> list;
res = NS_NewISupportsArray(getter_AddRefs(list));
while (NS_COMFALSE == iter->IsDone())
{
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIContent> content;
res = iter->CurrentNode(getter_AddRefs(content));
node = do_QueryInterface(content);
if ((NS_SUCCEEDED(res)) && node)
{
// can't manipulate tree while using subtree iterator, or we will
// confuse it's little mind
// instead chuck the results into an array.
list->AppendElement(node);
}
res = iter->Next();
if (NS_FAILED(res)) return res;
}
// use these ranges to contruct a list of nodes to act on.
nsCOMPtr<nsISupportsArray> arrayOfNodes;
res = GetNodesForOperation(arrayOfRanges, &arrayOfNodes, kOutdent);
if (NS_FAILED(res)) return res;
// Next we detect all the transitions in the array, where a transition
// means that adjacent nodes in the array don't have the same parent.
nsVoidArray transitionList;
res = MakeTransitionList(arrayOfNodes, &transitionList);
if (NS_FAILED(res)) return res;
// Ok, now go through all the nodes and remove a level of blockquoting,
// or whatever is appropriate. Wohoo!
PRUint32 listCount;
PRInt32 i;
list->Count(&listCount);
nsVoidArray transitionList;
nsCOMPtr<nsIDOMNode> prevElementParent;
nsCOMPtr<nsIDOMNode> curElementParent;
for (i=0; i<listCount; i++)
{
nsISupports *thingy;
thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> transNode( do_QueryInterface(thingy) );
transNode->GetParentNode(getter_AddRefs(curElementParent));
if (curElementParent != prevElementParent)
{
transitionList.InsertElementAt((void*)PR_TRUE,i); // different parents: transition point
}
else
{
transitionList.InsertElementAt((void*)PR_FALSE,i); // same parents: these nodes grew up together
}
prevElementParent = curElementParent;
}
// Ok, now go through all the lodes and remove a level of blockquoting,
// or whatever is appropriate. Wohoo!
arrayOfNodes->Count(&listCount);
nsCOMPtr<nsIDOMNode> curParent;
for (i=0; i<listCount; i++)
{
// here's where we actually figure out what to do
nsISupports *thingy;
thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(thingy) );
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
PRInt32 offset;
res = nsEditor::GetNodeLocation(curNode, &curParent, &offset);
if (NS_FAILED(res)) return res;
@ -1022,114 +800,40 @@ nsHTMLEditRules::WillAlign(nsIDOMSelection *aSelection, const nsString *alignTyp
nsAutoSelectionReset selectionResetter(aSelection);
nsresult res = NS_OK;
// get selection range - XXX generalize to collection of ranges
// gather up factoids about the range
nsCOMPtr<nsIDOMRange> selectionRange;
nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIDOMNode> endNode;
PRInt32 startOffset, endOffset;
// convert the selection ranges into "promoted" selection ranges:
// this basically just expands the range to include the immediate
// block parent, and then further expands to include any ancestors
// whose children are all in the range
res = aSelection->GetRangeAt(0,getter_AddRefs(selectionRange));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartParent(getter_AddRefs(startNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartOffset(&startOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndParent(getter_AddRefs(endNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndOffset(&endOffset);
nsCOMPtr<nsISupportsArray> arrayOfRanges;
res = GetPromotedRanges(aSelection, &arrayOfRanges, kAlign);
if (NS_FAILED(res)) return res;
// make a new adjusted range to represent the appropriate block content
// this is tricky. the basic idea is to push out the range endpoints
// to truly enclose the blocks that we will affect
nsCOMPtr<nsIDOMNode> quoteStartNode;
nsCOMPtr<nsIDOMNode> quoteEndNode;
PRInt32 quoteStartOffset, quoteEndOffset;
nsCOMPtr<nsIDOMRange> opRange;
res = GetPromotedPoint( kStart, startNode, startOffset, kIndent, &quoteStartNode, &quoteStartOffset);
if (NS_FAILED(res)) return res;
res = GetPromotedPoint( kEnd, endNode, endOffset, kIndent, &quoteEndNode, &quoteEndOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->Clone(getter_AddRefs(opRange));
if (NS_FAILED(res)) return res;
opRange->SetStart(quoteStartNode, quoteStartOffset);
if (NS_FAILED(res)) return res;
opRange->SetEnd(quoteEndNode, quoteEndOffset);
if (NS_FAILED(res)) return res;
// use subtree iterator to boogie over the snazzy new range
// we wil gather the top level nodes to process into an array
nsCOMPtr<nsIContentIterator> iter;
res = nsComponentManager::CreateInstance(kSubtreeIteratorCID,
nsnull,
nsIContentIterator::GetIID(),
getter_AddRefs(iter));
if (NS_FAILED(res)) return res;
res = iter->Init(opRange);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsISupportsArray> list;
res = NS_NewISupportsArray(getter_AddRefs(list));
while (NS_COMFALSE == iter->IsDone())
{
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIContent> content;
res = iter->CurrentNode(getter_AddRefs(content));
node = do_QueryInterface(content);
if ((NS_SUCCEEDED(res)) && node)
{
// can't manipulate tree while using subtree iterator, or we will
// confuse it's little mind
// instead chuck the results into an array.
list->AppendElement(node);
}
res = iter->Next();
if (NS_FAILED(res)) return res;
}
// use these ranges to contruct a list of nodes to act on.
nsCOMPtr<nsISupportsArray> arrayOfNodes;
res = GetNodesForOperation(arrayOfRanges, &arrayOfNodes, kAlign);
if (NS_FAILED(res)) return res;
// Next we detect all the transitions in the array, where a transition
// means that adjacent nodes in the array don't have the same parent.
PRUint32 listCount;
PRInt32 i;
list->Count(&listCount);
nsVoidArray transitionList;
nsCOMPtr<nsIDOMNode> prevElementParent;
nsCOMPtr<nsIDOMNode> curElementParent;
for (i=0; i<listCount; i++)
{
nsISupports *thingy;
thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> transNode( do_QueryInterface(thingy) );
transNode->GetParentNode(getter_AddRefs(curElementParent));
if (curElementParent != prevElementParent)
{
transitionList.InsertElementAt((void*)PR_TRUE,i); // different parents: transition point
}
else
{
transitionList.InsertElementAt((void*)PR_FALSE,i); // same parents: these nodes grew up together
}
prevElementParent = curElementParent;
}
// Ok, now go through all the lodes and give them an align attrib or put them in a div,
res = MakeTransitionList(arrayOfNodes, &transitionList);
if (NS_FAILED(res)) return res;
// Ok, now go through all the nodes and give them an align attrib or put them in a div,
// or whatever is appropriate. Wohoo!
PRUint32 listCount;
PRInt32 i;
arrayOfNodes->Count(&listCount);
nsCOMPtr<nsIDOMNode> curParent;
nsCOMPtr<nsIDOMNode> curDiv;
for (i=0; i<listCount; i++)
{
// here's where we actually figure out what to do
nsISupports *thingy;
thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(thingy) );
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
PRInt32 offset;
res = nsEditor::GetNodeLocation(curNode, &curParent, &offset);
if (NS_FAILED(res)) return res;
@ -1526,6 +1230,165 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetPromotedRanges: run all the selection range endpoint through
// GetPromotedPoint()
//
nsresult
nsHTMLEditRules::GetPromotedRanges(nsIDOMSelection *inSelection,
nsCOMPtr<nsISupportsArray> *outArrayOfRanges,
PRInt32 inOperationType)
{
if (!inSelection || !outArrayOfRanges) return NS_ERROR_NULL_POINTER;
nsresult res = NS_NewISupportsArray(getter_AddRefs(*outArrayOfRanges));
if (NS_FAILED(res)) return res;
PRInt32 rangeCount;
res = inSelection->GetRangeCount(&rangeCount);
if (NS_FAILED(res)) return res;
PRInt32 i;
nsCOMPtr<nsIDOMRange> selectionRange;
nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIDOMNode> endNode;
PRInt32 startOffset, endOffset;
for (i = 0; i < rangeCount; i++)
{
res = inSelection->GetRangeAt(i, getter_AddRefs(selectionRange));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartParent(getter_AddRefs(startNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartOffset(&startOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndParent(getter_AddRefs(endNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndOffset(&endOffset);
if (NS_FAILED(res)) return res;
// make a new adjusted range to represent the appropriate block content
// this is tricky. the basic idea is to push out the range endpoints
// to truly enclose the blocks that we will affect
nsCOMPtr<nsIDOMNode> opStartNode;
nsCOMPtr<nsIDOMNode> opEndNode;
PRInt32 opStartOffset, opEndOffset;
nsCOMPtr<nsIDOMRange> opRange;
res = GetPromotedPoint( kStart, startNode, startOffset, inOperationType, &opStartNode, &opStartOffset);
if (NS_FAILED(res)) return res;
res = GetPromotedPoint( kEnd, endNode, endOffset, inOperationType, &opEndNode, &opEndOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->Clone(getter_AddRefs(opRange));
if (NS_FAILED(res)) return res;
opRange->SetStart(opStartNode, opStartOffset);
if (NS_FAILED(res)) return res;
opRange->SetEnd(opEndNode, opEndOffset);
if (NS_FAILED(res)) return res;
// stuff new opRange into nsISupportsArray
nsCOMPtr<nsISupports> isupports = do_QueryInterface(opRange);
(*outArrayOfRanges)->AppendElement(isupports);
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetNodesForOperation: run through the ranges in the array and construct
// a new array of nodes to be acted on.
//
nsresult
nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
PRInt32 inOperationType)
{
if (!inArrayOfRanges || !outArrayOfNodes) return NS_ERROR_NULL_POINTER;
nsresult res = NS_NewISupportsArray(getter_AddRefs(*outArrayOfNodes));
if (NS_FAILED(res)) return res;
PRUint32 rangeCount;
res = inArrayOfRanges->Count(&rangeCount);
if (NS_FAILED(res)) return res;
PRInt32 i;
nsCOMPtr<nsIDOMRange> opRange;
nsCOMPtr<nsISupports> isupports;
nsCOMPtr<nsIContentIterator> iter;
for (i = 0; i < rangeCount; i++)
{
isupports = (dont_AddRef)(inArrayOfRanges->ElementAt(i));
opRange = do_QueryInterface(isupports);
res = nsComponentManager::CreateInstance(kSubtreeIteratorCID,
nsnull,
nsIContentIterator::GetIID(),
getter_AddRefs(iter));
if (NS_FAILED(res)) return res;
res = iter->Init(opRange);
if (NS_FAILED(res)) return res;
while (NS_COMFALSE == iter->IsDone())
{
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIContent> content;
res = iter->CurrentNode(getter_AddRefs(content));
node = do_QueryInterface(content);
if ((NS_SUCCEEDED(res)) && node)
{
isupports = do_QueryInterface(node);
(*outArrayOfNodes)->AppendElement(isupports);
}
res = iter->Next();
if (NS_FAILED(res)) return res;
}
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// MakeTransitionList: detect all the transitions in the array, where a
// transition means that adjacent nodes in the array
// don't have the same parent.
//
nsresult
nsHTMLEditRules::MakeTransitionList(nsISupportsArray *inArrayOfNodes,
nsVoidArray *inTransitionArray)
{
if (!inArrayOfNodes || !inTransitionArray) return NS_ERROR_NULL_POINTER;
PRUint32 listCount;
PRInt32 i;
inArrayOfNodes->Count(&listCount);
nsVoidArray transitionList;
nsCOMPtr<nsIDOMNode> prevElementParent;
nsCOMPtr<nsIDOMNode> curElementParent;
for (i=0; i<listCount; i++)
{
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(inArrayOfNodes->ElementAt(i));
nsCOMPtr<nsIDOMNode> transNode( do_QueryInterface(isupports ) );
transNode->GetParentNode(getter_AddRefs(curElementParent));
if (curElementParent != prevElementParent)
{
inTransitionArray->InsertElementAt((void*)PR_TRUE,i); // different parents: transition point
}
else
{
inTransitionArray->InsertElementAt((void*)PR_FALSE,i); // same parents: these nodes grew up together
}
prevElementParent = curElementParent;
}
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////
// ReplaceContainer: replace inNode with a new node (outNode) which is contructed
// to be of type aNodeType. Put inNodes children into outNode.
@ -1925,6 +1788,3 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,

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

@ -23,6 +23,7 @@
#include "nsCOMPtr.h"
class nsISupportsArray;
class nsVoidArray;
class nsHTMLEditRules : public nsTextEditRules
{
@ -93,6 +94,14 @@ protected:
static PRBool IsLastNode(nsIDOMNode *aNode);
static nsresult GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt32 aOffset,
PRInt32 actionID, nsCOMPtr<nsIDOMNode> *outNode, PRInt32 *outOffset);
static nsresult GetPromotedRanges(nsIDOMSelection *inSelection,
nsCOMPtr<nsISupportsArray> *outArrayOfRanges,
PRInt32 inOperationType);
static nsresult GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
PRInt32 inOperationType);
static nsresult MakeTransitionList(nsISupportsArray *inArrayOfNodes,
nsVoidArray *inTransitionArray);
nsresult ReplaceContainer(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, nsString &aNodeType);
nsresult RemoveContainer(nsIDOMNode *inNode);

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

@ -52,6 +52,7 @@ static NS_DEFINE_IID(kRangeListCID, NS_RANGELIST_CID);
nsTextEditRules::nsTextEditRules()
{
mEditor = nsnull;
mPINSelection = PR_TRUE;
mFlags=0;
}
@ -100,6 +101,15 @@ nsTextEditRules::WillDoAction(nsIDOMSelection *aSelection,
*aCancel = PR_FALSE;
// no matter what we are doing, sanity check the selection and force it
// to be inside the PRE element
if (mPINSelection)
{
nsresult res = PinSelectionInPRE(aSelection);
if (NS_FAILED(res)) return res;
}
// my kingdom for dynamic cast
nsTextRulesInfo *info = NS_STATIC_CAST(nsTextRulesInfo*, aInfo);
@ -925,3 +935,117 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection)
}
return result;
}
static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
nsresult
nsTextEditRules::PinSelectionInPRE(nsIDOMSelection *aSelection)
{
if (!aSelection)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMElement> preElement = mEditor->FindPreElement();
if (!preElement)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode> preNode = do_QueryInterface(preElement);
nsCOMPtr<nsIDOMRange> preRange;
nsresult res = nsComponentManager::CreateInstance(kRangeCID, nsnull,
nsIDOMRange::GetIID(),
getter_AddRefs(preRange));
if (NS_FAILED(res)) return res;
res = preRange->SelectNodeContents(preNode);
if (NS_FAILED(res)) return res;
PRInt32 len;
nsCOMPtr<nsIDOMRange> selectionRange;
nsCOMPtr<nsIDOMRange> pinRange;
res = preRange->GetEndOffset(&len);
if (NS_FAILED(res)) return res;
// there should only be one selection range in text docs
res = aSelection->GetRangeAt(0, getter_AddRefs(selectionRange));
if (NS_FAILED(res)) return res;
res = selectionRange->Clone(getter_AddRefs(pinRange));
if (NS_FAILED(res)) return res;
PRInt32 order;
PRBool needToPin = PR_FALSE;
res = preRange->CompareEndPoints(nsIDOMRange::END_TO_START, selectionRange, &order);
if (order > 0)
{
// start of range is after end of pre node; pin to end
res = pinRange->SetStart(preNode, len);
if (NS_FAILED(res)) return res;
needToPin = PR_TRUE;
}
res = preRange->CompareEndPoints(nsIDOMRange::START_TO_END, selectionRange, &order);
if (order < 0)
{
// end of range is before start of pre node; pin to start
res = pinRange->SetEnd(preNode, 0);
if (NS_FAILED(res)) return res;
needToPin = PR_TRUE;
}
res = preRange->CompareEndPoints(nsIDOMRange::START_TO_START, selectionRange, &order);
if (order < 0)
{
// start of range is before start of pre node; pin to start
res = pinRange->SetStart(preNode, 0);
if (NS_FAILED(res)) return res;
needToPin = PR_TRUE;
}
res = preRange->CompareEndPoints(nsIDOMRange::END_TO_END, selectionRange, &order);
if (order > 0)
{
// end of range is after end of pre node; pin to end
res = pinRange->SetEnd(preNode, len);
if (NS_FAILED(res)) return res;
needToPin = PR_TRUE;
}
if (needToPin)
{
nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIDOMNode> endNode;
PRInt32 startOffset, endOffset;
res = pinRange->GetStartParent(getter_AddRefs(startNode));
if (NS_FAILED(res)) return res;
res = pinRange->GetStartOffset(&startOffset);
if (NS_FAILED(res)) return res;
res = pinRange->GetEndParent(getter_AddRefs(endNode));
if (NS_FAILED(res)) return res;
res = pinRange->GetEndOffset(&endOffset);
if (NS_FAILED(res)) return res;
res = aSelection->Collapse(startNode,startOffset);
if (NS_FAILED(res)) return res;
res = aSelection->Extend(endNode,endOffset);
if (NS_FAILED(res)) return res;
}
return NS_OK;
}

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

@ -150,11 +150,15 @@ protected:
/** creates a bogus text node if the document has no editable content */
nsresult CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection);
/** enforce selection must be inside PRE node */
nsresult PinSelectionInPRE(nsIDOMSelection *aSelection);
// data
nsTextEditor *mEditor; // note that we do not refcount the editor
nsString mPasswordText; // a buffer we use to store the real value of password editors
nsCOMPtr<nsIDOMNode> mBogusNode; // magic node acts as placeholder in empty doc
PRUint32 mFlags;
PRBool mPINSelection; // whether to try to pin the selection inside a PRE tag
};

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

@ -1407,35 +1407,6 @@ NS_IMETHODIMP nsTextEditor::InsertAsQuotation(const nsString& aQuotedText)
return InsertText(quotedStuff);
}
// Useful helper method for Get/SetBodyWrapWidth:
static nsCOMPtr<nsIDOMElement>
findPreElement(nsIDOMDocument* domdoc)
{
nsCOMPtr<nsIDocument> doc (do_QueryInterface(domdoc));
if (!doc)
return 0;
nsIContent* rootContent = doc->GetRootContent();
if (!rootContent)
return 0;
nsCOMPtr<nsIDOMNode> rootNode (do_QueryInterface(rootContent));
if (!rootNode)
return 0;
nsString prestr ("PRE"); // GetFirstNodeOfType requires capitals
nsCOMPtr<nsIDOMNode> preNode;
if (!NS_SUCCEEDED(nsEditor::GetFirstNodeOfType(rootNode, prestr,
getter_AddRefs(preNode))))
{
#ifdef DEBUG_akkana
printf("No PRE tag\n");
#endif
return 0;
}
return do_QueryInterface(preNode);
}
//
// Get the wrap width for the first PRE tag in the document.
// If no PRE tag, throw an error.
@ -1447,12 +1418,7 @@ NS_IMETHODIMP nsTextEditor::GetBodyWrapWidth(PRUint32 *aWrapColumn)
if (! aWrapColumn)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMDocument> domdoc;
nsEditor::GetDocument(getter_AddRefs(domdoc));
if (!domdoc)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIDOMElement> preElement = findPreElement(domdoc);
nsCOMPtr<nsIDOMElement> preElement = FindPreElement();
if (!preElement)
return NS_ERROR_UNEXPECTED;
nsString colsStr ("cols");
@ -1506,12 +1472,7 @@ NS_IMETHODIMP nsTextEditor::SetBodyWrapWidth(PRUint32 aWrapColumn)
mWrapColumn = aWrapColumn;
nsCOMPtr<nsIDOMDocument> domdoc;
nsEditor::GetDocument(getter_AddRefs(domdoc));
if (!domdoc)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIDOMElement> preElement = findPreElement(domdoc);
nsCOMPtr<nsIDOMElement> preElement = FindPreElement();
if (!preElement)
return NS_ERROR_UNEXPECTED;
@ -1733,6 +1694,42 @@ NS_IMETHODIMP nsTextEditor::OutputHTMLToStream(nsIOutputStream* aOutputStream,ns
return encoder->EncodeToStream(aOutputStream);
}
nsCOMPtr<nsIDOMElement>
nsTextEditor::FindPreElement()
{
nsCOMPtr<nsIDOMDocument> domdoc;
nsEditor::GetDocument(getter_AddRefs(domdoc));
if (!domdoc)
return 0;
nsCOMPtr<nsIDocument> doc (do_QueryInterface(domdoc));
if (!doc)
return 0;
nsIContent* rootContent = doc->GetRootContent();
if (!rootContent)
return 0;
nsCOMPtr<nsIDOMNode> rootNode (do_QueryInterface(rootContent));
if (!rootNode)
return 0;
nsString prestr ("PRE"); // GetFirstNodeOfType requires capitals
nsCOMPtr<nsIDOMNode> preNode;
if (!NS_SUCCEEDED(nsEditor::GetFirstNodeOfType(rootNode, prestr,
getter_AddRefs(preNode))))
{
#ifdef DEBUG_akkana
printf("No PRE tag\n");
#endif
return 0;
}
return do_QueryInterface(preNode);
}
NS_IMETHODIMP nsTextEditor::SetTextPropertiesForNode(nsIDOMNode *aNode,
nsIDOMNode *aParent,
PRInt32 aStartOffset,

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

@ -129,6 +129,8 @@ public:
// End of methods implemented in nsEditor
//=============================================================
protected:
// file handling utils
@ -141,6 +143,11 @@ protected:
// Utility Methods
/** returns the PRE elements that bounds the content of the text document
* @param domdoc The text document
*/
nsCOMPtr<nsIDOMElement> FindPreElement();
/** content-based query returns PR_TRUE if <aProperty aAttribute=aValue> effects aNode
* If <aProperty aAttribute=aValue> contains aNode,
* but <aProperty aAttribute=SomeOtherValue> also contains aNode and the second is

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

@ -60,6 +60,7 @@ enum
nsHTMLEditRules::nsHTMLEditRules()
{
mPINSelection = PR_FALSE;
}
nsHTMLEditRules::~nsHTMLEditRules()
@ -452,85 +453,27 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
*aCancel = PR_TRUE;
nsAutoSelectionReset selectionResetter(aSelection);
nsresult res = NS_OK;
nsresult res;
// get selection range - XXX generalize to collection of ranges
// gather up factoids about the range
nsCOMPtr<nsIDOMRange> selectionRange;
nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIDOMNode> endNode;
nsCOMPtr<nsIDOMNode> commonParent;
PRInt32 startOffset, endOffset;
// convert the selection ranges into "promoted" selection ranges:
// this basically just expands the range to include the immediate
// block parent, and then further expands to include any ancestors
// whose children are all in the range
res = aSelection->GetRangeAt(0,getter_AddRefs(selectionRange));
nsCOMPtr<nsISupportsArray> arrayOfRanges;
res = GetPromotedRanges(aSelection, &arrayOfRanges, kMakeList);
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartParent(getter_AddRefs(startNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartOffset(&startOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndParent(getter_AddRefs(endNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndOffset(&endOffset);
if (NS_FAILED(res)) return res;
// res = selectionRange->GetCommonParent(getter_AddRefs(commonParent));
// if (NS_FAILED(res)) return res;
// make a new adjusted range to represent the appropriate block content
// this is tricky. the basic idea is to push out the range endpoints
// to truly enclose the blocks that we will affect
nsCOMPtr<nsIDOMNode> listStartNode;
nsCOMPtr<nsIDOMNode> listEndNode;
PRInt32 listStartOffset, listEndOffset;
nsCOMPtr<nsIDOMRange> opRange;
res = GetPromotedPoint( kStart, startNode, startOffset, kMakeList, &listStartNode, &listStartOffset);
if (NS_FAILED(res)) return res;
res = GetPromotedPoint( kEnd, endNode, endOffset, kMakeList, &listEndNode, &listEndOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->Clone(getter_AddRefs(opRange));
if (NS_FAILED(res)) return res;
opRange->SetStart(listStartNode, listStartOffset);
if (NS_FAILED(res)) return res;
opRange->SetEnd(listEndNode, listEndOffset);
if (NS_FAILED(res)) return res;
// use subtree iterator to boogie over the snazzy new range
// we wil gather the top level nodes to process into a list
nsCOMPtr<nsIContentIterator> iter;
res = nsComponentManager::CreateInstance(kSubtreeIteratorCID,
nsnull,
nsIContentIterator::GetIID(),
getter_AddRefs(iter));
if (NS_FAILED(res)) return res;
res = iter->Init(opRange);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsISupportsArray> list;
res = NS_NewISupportsArray(getter_AddRefs(list));
while (NS_COMFALSE == iter->IsDone())
{
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIContent> content;
res = iter->CurrentNode(getter_AddRefs(content));
node = do_QueryInterface(content);
if ((NS_SUCCEEDED(res)) && node)
{
// can't manipulate tree while using subtree iterator, or we will
// confuse it's little mind
// instead chuck the results into an array.
list->AppendElement(node);
}
res = iter->Next();
if (NS_FAILED(res)) return res;
}
// use these ranges to contruct a list of nodes to act on.
nsCOMPtr<nsISupportsArray> arrayOfNodes;
res = GetNodesForOperation(arrayOfRanges, &arrayOfNodes, kMakeList);
if (NS_FAILED(res)) return res;
// if we ended up with any nodes in the list that aren't blocknodes,
// find their block parent instead and use that.
// i started writing this and then the sky fell. there are big questions
// about what to do here. i may need to switch rom think about an array of
// about what to do here. i may need to switch from thinking about an array of
// nodes to act on to instead think of an array of ranges to act on.
// Next we remove all the <br>'s in the array. This won't prevent <br>'s
@ -541,28 +484,28 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
PRUint32 listCount;
PRInt32 i;
list->Count(&listCount);
arrayOfNodes->Count(&listCount);
for (i=listCount-1; i>=0; i--)
{
nsISupports *thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> testNode( do_QueryInterface(thingy) );
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
nsCOMPtr<nsIDOMNode> testNode( do_QueryInterface(isupports ) );
if (IsBreak(testNode))
{
list->RemoveElementAt(i);
arrayOfNodes->RemoveElementAt(i);
}
else if (!nsEditor::IsEditable(testNode))
{
list->RemoveElementAt(i);
arrayOfNodes->RemoveElementAt(i);
}
}
// if there is only one node in the array, and it is a list, div, or blockquote,
// then look inside of it until we find what we want to make a list out of.
arrayOfNodes->Count(&listCount);
if (listCount == 1)
{
nsISupports *thingy;
thingy = list->ElementAt(0);
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(thingy) );
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
while (IsDiv(curNode) || IsOrderedList(curNode) || IsUnorderedList(curNode) || IsBlockquote(curNode))
{
@ -575,57 +518,40 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
{
// keep diving
nsCOMPtr <nsIDOMNode> tmpNode = nsEditor::GetChildAt(curNode, 0);
// check editablility XXX moose
curNode = tmpNode;
}
else
{
// stop diving
break;
if (IsDiv(tmpNode) || IsOrderedList(tmpNode) || IsUnorderedList(tmpNode) || IsBlockquote(tmpNode))
{
// check editablility XXX moose
curNode = tmpNode;
}
else break;
}
else break;
}
// we've found innermost list/blockquote/div:
// replace the one node in the array with this node
list->ReplaceElementAt(curNode, 0);
isupports = do_QueryInterface(curNode);
arrayOfNodes->ReplaceElementAt(isupports, 0);
}
// Next we detect all the transitions in the array, where a transition
// means that adjacent nodes in the array don't have the same parent.
list->Count(&listCount);
nsVoidArray transitionList;
nsCOMPtr<nsIDOMNode> prevElementParent;
nsCOMPtr<nsIDOMNode> curElementParent;
for (i=0; i<listCount; i++)
{
nsISupports *thingy;
thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> transNode( do_QueryInterface(thingy) );
transNode->GetParentNode(getter_AddRefs(curElementParent));
if (curElementParent != prevElementParent)
{
transitionList.InsertElementAt((void*)PR_TRUE,i); // different parents: transition point
}
else
{
transitionList.InsertElementAt((void*)PR_FALSE,i); // same parents: these nodes grew up together
}
prevElementParent = curElementParent;
}
res = MakeTransitionList(arrayOfNodes, &transitionList);
if (NS_FAILED(res)) return res;
// Ok, now go through all the nodes and put then in the list,
// or whatever is approriate. Wohoo!
arrayOfNodes->Count(&listCount);
nsCOMPtr<nsIDOMNode> curParent;
nsCOMPtr<nsIDOMNode> curList;
for (i=0; i<listCount; i++)
{
// here's where we actually figure out what to do
nsISupports *thingy;
thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(thingy) );
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
PRInt32 offset;
res = nsEditor::GetNodeLocation(curNode, &curParent, &offset);
if (NS_FAILED(res)) return res;
@ -730,116 +656,42 @@ nsHTMLEditRules::WillIndent(nsIDOMSelection *aSelection, PRBool *aCancel)
*aCancel = PR_TRUE;
nsAutoSelectionReset selectionResetter(aSelection);
nsresult res = NS_OK;
nsresult res;
// get selection range - XXX generalize to collection of ranges
// gather up factoids about the range
nsCOMPtr<nsIDOMRange> selectionRange;
nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIDOMNode> endNode;
PRInt32 startOffset, endOffset;
// convert the selection ranges into "promoted" selection ranges:
// this basically just expands the range to include the immediate
// block parent, and then further expands to include any ancestors
// whose children are all in the range
res = aSelection->GetRangeAt(0,getter_AddRefs(selectionRange));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartParent(getter_AddRefs(startNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartOffset(&startOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndParent(getter_AddRefs(endNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndOffset(&endOffset);
nsCOMPtr<nsISupportsArray> arrayOfRanges;
res = GetPromotedRanges(aSelection, &arrayOfRanges, kIndent);
if (NS_FAILED(res)) return res;
// make a new adjusted range to represent the appropriate block content
// this is tricky. the basic idea is to push out the range endpoints
// to truly enclose the blocks that we will affect
nsCOMPtr<nsIDOMNode> quoteStartNode;
nsCOMPtr<nsIDOMNode> quoteEndNode;
PRInt32 quoteStartOffset, quoteEndOffset;
nsCOMPtr<nsIDOMRange> opRange;
res = GetPromotedPoint( kStart, startNode, startOffset, kIndent, &quoteStartNode, &quoteStartOffset);
if (NS_FAILED(res)) return res;
res = GetPromotedPoint( kEnd, endNode, endOffset, kIndent, &quoteEndNode, &quoteEndOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->Clone(getter_AddRefs(opRange));
if (NS_FAILED(res)) return res;
opRange->SetStart(quoteStartNode, quoteStartOffset);
if (NS_FAILED(res)) return res;
opRange->SetEnd(quoteEndNode, quoteEndOffset);
if (NS_FAILED(res)) return res;
// use subtree iterator to boogie over the snazzy new range
// we wil gather the top level nodes to process into an array
nsCOMPtr<nsIContentIterator> iter;
res = nsComponentManager::CreateInstance(kSubtreeIteratorCID,
nsnull,
nsIContentIterator::GetIID(),
getter_AddRefs(iter));
if (NS_FAILED(res)) return res;
res = iter->Init(opRange);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsISupportsArray> list;
res = NS_NewISupportsArray(getter_AddRefs(list));
while (NS_COMFALSE == iter->IsDone())
{
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIContent> content;
res = iter->CurrentNode(getter_AddRefs(content));
node = do_QueryInterface(content);
if ((NS_SUCCEEDED(res)) && node)
{
// can't manipulate tree while using subtree iterator, or we will
// confuse it's little mind
// instead chuck the results into an array.
list->AppendElement(node);
}
res = iter->Next();
if (NS_FAILED(res)) return res;
}
// use these ranges to contruct a list of nodes to act on.
nsCOMPtr<nsISupportsArray> arrayOfNodes;
res = GetNodesForOperation(arrayOfRanges, &arrayOfNodes, kIndent);
if (NS_FAILED(res)) return res;
// Next we detect all the transitions in the array, where a transition
// means that adjacent nodes in the array don't have the same parent.
nsVoidArray transitionList;
res = MakeTransitionList(arrayOfNodes, &transitionList);
if (NS_FAILED(res)) return res;
// Ok, now go through all the nodes and put them in a blockquote,
// or whatever is appropriate. Wohoo!
PRUint32 listCount;
PRInt32 i;
list->Count(&listCount);
nsVoidArray transitionList;
nsCOMPtr<nsIDOMNode> prevElementParent;
nsCOMPtr<nsIDOMNode> curElementParent;
for (i=0; i<listCount; i++)
{
nsISupports *thingy;
thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> transNode( do_QueryInterface(thingy) );
transNode->GetParentNode(getter_AddRefs(curElementParent));
if (curElementParent != prevElementParent)
{
transitionList.InsertElementAt((void*)PR_TRUE,i); // different parents: transition point
}
else
{
transitionList.InsertElementAt((void*)PR_FALSE,i); // same parents: these nodes grew up together
}
prevElementParent = curElementParent;
}
// Ok, now go through all the lodes and put them in a blockquote,
// or whatever is appropriate. Wohoo!
arrayOfNodes->Count(&listCount);
nsCOMPtr<nsIDOMNode> curParent;
nsCOMPtr<nsIDOMNode> curQuote;
for (i=0; i<listCount; i++)
{
// here's where we actually figure out what to do
nsISupports *thingy;
thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(thingy) );
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
PRInt32 offset;
res = nsEditor::GetNodeLocation(curNode, &curParent, &offset);
if (NS_FAILED(res)) return res;
@ -878,113 +730,39 @@ nsHTMLEditRules::WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel)
nsAutoSelectionReset selectionResetter(aSelection);
nsresult res = NS_OK;
// get selection range - XXX generalize to collection of ranges
// gather up factoids about the range
nsCOMPtr<nsIDOMRange> selectionRange;
nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIDOMNode> endNode;
PRInt32 startOffset, endOffset;
// convert the selection ranges into "promoted" selection ranges:
// this basically just expands the range to include the immediate
// block parent, and then further expands to include any ancestors
// whose children are all in the range
res = aSelection->GetRangeAt(0,getter_AddRefs(selectionRange));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartParent(getter_AddRefs(startNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartOffset(&startOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndParent(getter_AddRefs(endNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndOffset(&endOffset);
nsCOMPtr<nsISupportsArray> arrayOfRanges;
res = GetPromotedRanges(aSelection, &arrayOfRanges, kOutdent);
if (NS_FAILED(res)) return res;
// make a new adjusted range to represent the appropriate block content
// this is tricky. the basic idea is to push out the range endpoints
// to truly enclose the blocks that we will affect
nsCOMPtr<nsIDOMNode> quoteStartNode;
nsCOMPtr<nsIDOMNode> quoteEndNode;
PRInt32 quoteStartOffset, quoteEndOffset;
nsCOMPtr<nsIDOMRange> opRange;
res = GetPromotedPoint( kStart, startNode, startOffset, kIndent, &quoteStartNode, &quoteStartOffset);
if (NS_FAILED(res)) return res;
res = GetPromotedPoint( kEnd, endNode, endOffset, kIndent, &quoteEndNode, &quoteEndOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->Clone(getter_AddRefs(opRange));
if (NS_FAILED(res)) return res;
opRange->SetStart(quoteStartNode, quoteStartOffset);
if (NS_FAILED(res)) return res;
opRange->SetEnd(quoteEndNode, quoteEndOffset);
if (NS_FAILED(res)) return res;
// use subtree iterator to boogie over the snazzy new range
// we wil gather the top level nodes to process into an array
nsCOMPtr<nsIContentIterator> iter;
res = nsComponentManager::CreateInstance(kSubtreeIteratorCID,
nsnull,
nsIContentIterator::GetIID(),
getter_AddRefs(iter));
if (NS_FAILED(res)) return res;
res = iter->Init(opRange);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsISupportsArray> list;
res = NS_NewISupportsArray(getter_AddRefs(list));
while (NS_COMFALSE == iter->IsDone())
{
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIContent> content;
res = iter->CurrentNode(getter_AddRefs(content));
node = do_QueryInterface(content);
if ((NS_SUCCEEDED(res)) && node)
{
// can't manipulate tree while using subtree iterator, or we will
// confuse it's little mind
// instead chuck the results into an array.
list->AppendElement(node);
}
res = iter->Next();
if (NS_FAILED(res)) return res;
}
// use these ranges to contruct a list of nodes to act on.
nsCOMPtr<nsISupportsArray> arrayOfNodes;
res = GetNodesForOperation(arrayOfRanges, &arrayOfNodes, kOutdent);
if (NS_FAILED(res)) return res;
// Next we detect all the transitions in the array, where a transition
// means that adjacent nodes in the array don't have the same parent.
nsVoidArray transitionList;
res = MakeTransitionList(arrayOfNodes, &transitionList);
if (NS_FAILED(res)) return res;
// Ok, now go through all the nodes and remove a level of blockquoting,
// or whatever is appropriate. Wohoo!
PRUint32 listCount;
PRInt32 i;
list->Count(&listCount);
nsVoidArray transitionList;
nsCOMPtr<nsIDOMNode> prevElementParent;
nsCOMPtr<nsIDOMNode> curElementParent;
for (i=0; i<listCount; i++)
{
nsISupports *thingy;
thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> transNode( do_QueryInterface(thingy) );
transNode->GetParentNode(getter_AddRefs(curElementParent));
if (curElementParent != prevElementParent)
{
transitionList.InsertElementAt((void*)PR_TRUE,i); // different parents: transition point
}
else
{
transitionList.InsertElementAt((void*)PR_FALSE,i); // same parents: these nodes grew up together
}
prevElementParent = curElementParent;
}
// Ok, now go through all the lodes and remove a level of blockquoting,
// or whatever is appropriate. Wohoo!
arrayOfNodes->Count(&listCount);
nsCOMPtr<nsIDOMNode> curParent;
for (i=0; i<listCount; i++)
{
// here's where we actually figure out what to do
nsISupports *thingy;
thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(thingy) );
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
PRInt32 offset;
res = nsEditor::GetNodeLocation(curNode, &curParent, &offset);
if (NS_FAILED(res)) return res;
@ -1022,114 +800,40 @@ nsHTMLEditRules::WillAlign(nsIDOMSelection *aSelection, const nsString *alignTyp
nsAutoSelectionReset selectionResetter(aSelection);
nsresult res = NS_OK;
// get selection range - XXX generalize to collection of ranges
// gather up factoids about the range
nsCOMPtr<nsIDOMRange> selectionRange;
nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIDOMNode> endNode;
PRInt32 startOffset, endOffset;
// convert the selection ranges into "promoted" selection ranges:
// this basically just expands the range to include the immediate
// block parent, and then further expands to include any ancestors
// whose children are all in the range
res = aSelection->GetRangeAt(0,getter_AddRefs(selectionRange));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartParent(getter_AddRefs(startNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartOffset(&startOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndParent(getter_AddRefs(endNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndOffset(&endOffset);
nsCOMPtr<nsISupportsArray> arrayOfRanges;
res = GetPromotedRanges(aSelection, &arrayOfRanges, kAlign);
if (NS_FAILED(res)) return res;
// make a new adjusted range to represent the appropriate block content
// this is tricky. the basic idea is to push out the range endpoints
// to truly enclose the blocks that we will affect
nsCOMPtr<nsIDOMNode> quoteStartNode;
nsCOMPtr<nsIDOMNode> quoteEndNode;
PRInt32 quoteStartOffset, quoteEndOffset;
nsCOMPtr<nsIDOMRange> opRange;
res = GetPromotedPoint( kStart, startNode, startOffset, kIndent, &quoteStartNode, &quoteStartOffset);
if (NS_FAILED(res)) return res;
res = GetPromotedPoint( kEnd, endNode, endOffset, kIndent, &quoteEndNode, &quoteEndOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->Clone(getter_AddRefs(opRange));
if (NS_FAILED(res)) return res;
opRange->SetStart(quoteStartNode, quoteStartOffset);
if (NS_FAILED(res)) return res;
opRange->SetEnd(quoteEndNode, quoteEndOffset);
if (NS_FAILED(res)) return res;
// use subtree iterator to boogie over the snazzy new range
// we wil gather the top level nodes to process into an array
nsCOMPtr<nsIContentIterator> iter;
res = nsComponentManager::CreateInstance(kSubtreeIteratorCID,
nsnull,
nsIContentIterator::GetIID(),
getter_AddRefs(iter));
if (NS_FAILED(res)) return res;
res = iter->Init(opRange);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsISupportsArray> list;
res = NS_NewISupportsArray(getter_AddRefs(list));
while (NS_COMFALSE == iter->IsDone())
{
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIContent> content;
res = iter->CurrentNode(getter_AddRefs(content));
node = do_QueryInterface(content);
if ((NS_SUCCEEDED(res)) && node)
{
// can't manipulate tree while using subtree iterator, or we will
// confuse it's little mind
// instead chuck the results into an array.
list->AppendElement(node);
}
res = iter->Next();
if (NS_FAILED(res)) return res;
}
// use these ranges to contruct a list of nodes to act on.
nsCOMPtr<nsISupportsArray> arrayOfNodes;
res = GetNodesForOperation(arrayOfRanges, &arrayOfNodes, kAlign);
if (NS_FAILED(res)) return res;
// Next we detect all the transitions in the array, where a transition
// means that adjacent nodes in the array don't have the same parent.
PRUint32 listCount;
PRInt32 i;
list->Count(&listCount);
nsVoidArray transitionList;
nsCOMPtr<nsIDOMNode> prevElementParent;
nsCOMPtr<nsIDOMNode> curElementParent;
for (i=0; i<listCount; i++)
{
nsISupports *thingy;
thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> transNode( do_QueryInterface(thingy) );
transNode->GetParentNode(getter_AddRefs(curElementParent));
if (curElementParent != prevElementParent)
{
transitionList.InsertElementAt((void*)PR_TRUE,i); // different parents: transition point
}
else
{
transitionList.InsertElementAt((void*)PR_FALSE,i); // same parents: these nodes grew up together
}
prevElementParent = curElementParent;
}
// Ok, now go through all the lodes and give them an align attrib or put them in a div,
res = MakeTransitionList(arrayOfNodes, &transitionList);
if (NS_FAILED(res)) return res;
// Ok, now go through all the nodes and give them an align attrib or put them in a div,
// or whatever is appropriate. Wohoo!
PRUint32 listCount;
PRInt32 i;
arrayOfNodes->Count(&listCount);
nsCOMPtr<nsIDOMNode> curParent;
nsCOMPtr<nsIDOMNode> curDiv;
for (i=0; i<listCount; i++)
{
// here's where we actually figure out what to do
nsISupports *thingy;
thingy = list->ElementAt(i);
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(thingy) );
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
PRInt32 offset;
res = nsEditor::GetNodeLocation(curNode, &curParent, &offset);
if (NS_FAILED(res)) return res;
@ -1526,6 +1230,165 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetPromotedRanges: run all the selection range endpoint through
// GetPromotedPoint()
//
nsresult
nsHTMLEditRules::GetPromotedRanges(nsIDOMSelection *inSelection,
nsCOMPtr<nsISupportsArray> *outArrayOfRanges,
PRInt32 inOperationType)
{
if (!inSelection || !outArrayOfRanges) return NS_ERROR_NULL_POINTER;
nsresult res = NS_NewISupportsArray(getter_AddRefs(*outArrayOfRanges));
if (NS_FAILED(res)) return res;
PRInt32 rangeCount;
res = inSelection->GetRangeCount(&rangeCount);
if (NS_FAILED(res)) return res;
PRInt32 i;
nsCOMPtr<nsIDOMRange> selectionRange;
nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIDOMNode> endNode;
PRInt32 startOffset, endOffset;
for (i = 0; i < rangeCount; i++)
{
res = inSelection->GetRangeAt(i, getter_AddRefs(selectionRange));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartParent(getter_AddRefs(startNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetStartOffset(&startOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndParent(getter_AddRefs(endNode));
if (NS_FAILED(res)) return res;
res = selectionRange->GetEndOffset(&endOffset);
if (NS_FAILED(res)) return res;
// make a new adjusted range to represent the appropriate block content
// this is tricky. the basic idea is to push out the range endpoints
// to truly enclose the blocks that we will affect
nsCOMPtr<nsIDOMNode> opStartNode;
nsCOMPtr<nsIDOMNode> opEndNode;
PRInt32 opStartOffset, opEndOffset;
nsCOMPtr<nsIDOMRange> opRange;
res = GetPromotedPoint( kStart, startNode, startOffset, inOperationType, &opStartNode, &opStartOffset);
if (NS_FAILED(res)) return res;
res = GetPromotedPoint( kEnd, endNode, endOffset, inOperationType, &opEndNode, &opEndOffset);
if (NS_FAILED(res)) return res;
res = selectionRange->Clone(getter_AddRefs(opRange));
if (NS_FAILED(res)) return res;
opRange->SetStart(opStartNode, opStartOffset);
if (NS_FAILED(res)) return res;
opRange->SetEnd(opEndNode, opEndOffset);
if (NS_FAILED(res)) return res;
// stuff new opRange into nsISupportsArray
nsCOMPtr<nsISupports> isupports = do_QueryInterface(opRange);
(*outArrayOfRanges)->AppendElement(isupports);
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// GetNodesForOperation: run through the ranges in the array and construct
// a new array of nodes to be acted on.
//
nsresult
nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
PRInt32 inOperationType)
{
if (!inArrayOfRanges || !outArrayOfNodes) return NS_ERROR_NULL_POINTER;
nsresult res = NS_NewISupportsArray(getter_AddRefs(*outArrayOfNodes));
if (NS_FAILED(res)) return res;
PRUint32 rangeCount;
res = inArrayOfRanges->Count(&rangeCount);
if (NS_FAILED(res)) return res;
PRInt32 i;
nsCOMPtr<nsIDOMRange> opRange;
nsCOMPtr<nsISupports> isupports;
nsCOMPtr<nsIContentIterator> iter;
for (i = 0; i < rangeCount; i++)
{
isupports = (dont_AddRef)(inArrayOfRanges->ElementAt(i));
opRange = do_QueryInterface(isupports);
res = nsComponentManager::CreateInstance(kSubtreeIteratorCID,
nsnull,
nsIContentIterator::GetIID(),
getter_AddRefs(iter));
if (NS_FAILED(res)) return res;
res = iter->Init(opRange);
if (NS_FAILED(res)) return res;
while (NS_COMFALSE == iter->IsDone())
{
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIContent> content;
res = iter->CurrentNode(getter_AddRefs(content));
node = do_QueryInterface(content);
if ((NS_SUCCEEDED(res)) && node)
{
isupports = do_QueryInterface(node);
(*outArrayOfNodes)->AppendElement(isupports);
}
res = iter->Next();
if (NS_FAILED(res)) return res;
}
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// MakeTransitionList: detect all the transitions in the array, where a
// transition means that adjacent nodes in the array
// don't have the same parent.
//
nsresult
nsHTMLEditRules::MakeTransitionList(nsISupportsArray *inArrayOfNodes,
nsVoidArray *inTransitionArray)
{
if (!inArrayOfNodes || !inTransitionArray) return NS_ERROR_NULL_POINTER;
PRUint32 listCount;
PRInt32 i;
inArrayOfNodes->Count(&listCount);
nsVoidArray transitionList;
nsCOMPtr<nsIDOMNode> prevElementParent;
nsCOMPtr<nsIDOMNode> curElementParent;
for (i=0; i<listCount; i++)
{
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(inArrayOfNodes->ElementAt(i));
nsCOMPtr<nsIDOMNode> transNode( do_QueryInterface(isupports ) );
transNode->GetParentNode(getter_AddRefs(curElementParent));
if (curElementParent != prevElementParent)
{
inTransitionArray->InsertElementAt((void*)PR_TRUE,i); // different parents: transition point
}
else
{
inTransitionArray->InsertElementAt((void*)PR_FALSE,i); // same parents: these nodes grew up together
}
prevElementParent = curElementParent;
}
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////
// ReplaceContainer: replace inNode with a new node (outNode) which is contructed
// to be of type aNodeType. Put inNodes children into outNode.
@ -1925,6 +1788,3 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,

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

@ -23,6 +23,7 @@
#include "nsCOMPtr.h"
class nsISupportsArray;
class nsVoidArray;
class nsHTMLEditRules : public nsTextEditRules
{
@ -93,6 +94,14 @@ protected:
static PRBool IsLastNode(nsIDOMNode *aNode);
static nsresult GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt32 aOffset,
PRInt32 actionID, nsCOMPtr<nsIDOMNode> *outNode, PRInt32 *outOffset);
static nsresult GetPromotedRanges(nsIDOMSelection *inSelection,
nsCOMPtr<nsISupportsArray> *outArrayOfRanges,
PRInt32 inOperationType);
static nsresult GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
PRInt32 inOperationType);
static nsresult MakeTransitionList(nsISupportsArray *inArrayOfNodes,
nsVoidArray *inTransitionArray);
nsresult ReplaceContainer(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, nsString &aNodeType);
nsresult RemoveContainer(nsIDOMNode *inNode);

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

@ -52,6 +52,7 @@ static NS_DEFINE_IID(kRangeListCID, NS_RANGELIST_CID);
nsTextEditRules::nsTextEditRules()
{
mEditor = nsnull;
mPINSelection = PR_TRUE;
mFlags=0;
}
@ -100,6 +101,15 @@ nsTextEditRules::WillDoAction(nsIDOMSelection *aSelection,
*aCancel = PR_FALSE;
// no matter what we are doing, sanity check the selection and force it
// to be inside the PRE element
if (mPINSelection)
{
nsresult res = PinSelectionInPRE(aSelection);
if (NS_FAILED(res)) return res;
}
// my kingdom for dynamic cast
nsTextRulesInfo *info = NS_STATIC_CAST(nsTextRulesInfo*, aInfo);
@ -925,3 +935,117 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection)
}
return result;
}
static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
nsresult
nsTextEditRules::PinSelectionInPRE(nsIDOMSelection *aSelection)
{
if (!aSelection)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMElement> preElement = mEditor->FindPreElement();
if (!preElement)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode> preNode = do_QueryInterface(preElement);
nsCOMPtr<nsIDOMRange> preRange;
nsresult res = nsComponentManager::CreateInstance(kRangeCID, nsnull,
nsIDOMRange::GetIID(),
getter_AddRefs(preRange));
if (NS_FAILED(res)) return res;
res = preRange->SelectNodeContents(preNode);
if (NS_FAILED(res)) return res;
PRInt32 len;
nsCOMPtr<nsIDOMRange> selectionRange;
nsCOMPtr<nsIDOMRange> pinRange;
res = preRange->GetEndOffset(&len);
if (NS_FAILED(res)) return res;
// there should only be one selection range in text docs
res = aSelection->GetRangeAt(0, getter_AddRefs(selectionRange));
if (NS_FAILED(res)) return res;
res = selectionRange->Clone(getter_AddRefs(pinRange));
if (NS_FAILED(res)) return res;
PRInt32 order;
PRBool needToPin = PR_FALSE;
res = preRange->CompareEndPoints(nsIDOMRange::END_TO_START, selectionRange, &order);
if (order > 0)
{
// start of range is after end of pre node; pin to end
res = pinRange->SetStart(preNode, len);
if (NS_FAILED(res)) return res;
needToPin = PR_TRUE;
}
res = preRange->CompareEndPoints(nsIDOMRange::START_TO_END, selectionRange, &order);
if (order < 0)
{
// end of range is before start of pre node; pin to start
res = pinRange->SetEnd(preNode, 0);
if (NS_FAILED(res)) return res;
needToPin = PR_TRUE;
}
res = preRange->CompareEndPoints(nsIDOMRange::START_TO_START, selectionRange, &order);
if (order < 0)
{
// start of range is before start of pre node; pin to start
res = pinRange->SetStart(preNode, 0);
if (NS_FAILED(res)) return res;
needToPin = PR_TRUE;
}
res = preRange->CompareEndPoints(nsIDOMRange::END_TO_END, selectionRange, &order);
if (order > 0)
{
// end of range is after end of pre node; pin to end
res = pinRange->SetEnd(preNode, len);
if (NS_FAILED(res)) return res;
needToPin = PR_TRUE;
}
if (needToPin)
{
nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIDOMNode> endNode;
PRInt32 startOffset, endOffset;
res = pinRange->GetStartParent(getter_AddRefs(startNode));
if (NS_FAILED(res)) return res;
res = pinRange->GetStartOffset(&startOffset);
if (NS_FAILED(res)) return res;
res = pinRange->GetEndParent(getter_AddRefs(endNode));
if (NS_FAILED(res)) return res;
res = pinRange->GetEndOffset(&endOffset);
if (NS_FAILED(res)) return res;
res = aSelection->Collapse(startNode,startOffset);
if (NS_FAILED(res)) return res;
res = aSelection->Extend(endNode,endOffset);
if (NS_FAILED(res)) return res;
}
return NS_OK;
}

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

@ -150,11 +150,15 @@ protected:
/** creates a bogus text node if the document has no editable content */
nsresult CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection);
/** enforce selection must be inside PRE node */
nsresult PinSelectionInPRE(nsIDOMSelection *aSelection);
// data
nsTextEditor *mEditor; // note that we do not refcount the editor
nsString mPasswordText; // a buffer we use to store the real value of password editors
nsCOMPtr<nsIDOMNode> mBogusNode; // magic node acts as placeholder in empty doc
PRUint32 mFlags;
PRBool mPINSelection; // whether to try to pin the selection inside a PRE tag
};