mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-18 06:45:33 +00:00
some reorg of block transformation code; implemented make-{header,preformatted,address,normal}; tweaked make list to honor <br> in some circumstances; rewrote "return in list item" to pop you out of list if item is empty; rewrote "return in header" to work with non-trivial headers.
This commit is contained in:
parent
d993dbf90c
commit
a099b1e5b6
@ -3153,7 +3153,8 @@ nsEditor::GetTag(nsIDOMNode *aNode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
|
||||||
content->GetTag(*getter_AddRefs(atom));
|
if (content)
|
||||||
|
content->GetTag(*getter_AddRefs(atom));
|
||||||
|
|
||||||
return atom;
|
return atom;
|
||||||
}
|
}
|
||||||
@ -3407,7 +3408,7 @@ nsEditor::NextNodeInBlock(nsIDOMNode *aNode, IterDirection aDir)
|
|||||||
if (NS_FAILED(iter->CurrentNode(getter_AddRefs(content)))) return nullNode;
|
if (NS_FAILED(iter->CurrentNode(getter_AddRefs(content)))) return nullNode;
|
||||||
// ignore nodes that aren't elements or text, or that are the block parent
|
// ignore nodes that aren't elements or text, or that are the block parent
|
||||||
node = do_QueryInterface(content);
|
node = do_QueryInterface(content);
|
||||||
if (node && IsTextOrElementNode(node) && (node != blockParent) && (node!=nsCOMPtr<nsIDOMNode>(dont_QueryInterface(aNode))))
|
if (node && IsTextOrElementNode(node) && (node != blockParent) && (node.get() != aNode))
|
||||||
return node;
|
return node;
|
||||||
|
|
||||||
if (aDir == kIterForward)
|
if (aDir == kIterForward)
|
||||||
@ -3680,7 +3681,7 @@ nsEditor::SplitNodeDeep(nsIDOMNode *aNode,
|
|||||||
if (!nodeAsText || (offset && (offset != textLen)))
|
if (!nodeAsText || (offset && (offset != textLen)))
|
||||||
{
|
{
|
||||||
bDoSplit = PR_TRUE;
|
bDoSplit = PR_TRUE;
|
||||||
nsresult res = SplitNode(nodeToSplit, offset, getter_AddRefs(tempNode));
|
res = SplitNode(nodeToSplit, offset, getter_AddRefs(tempNode));
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,12 +107,8 @@ nsHTMLEditRules::WillDoAction(nsIDOMSelection *aSelection,
|
|||||||
return WillOutdent(aSelection, aCancel);
|
return WillOutdent(aSelection, aCancel);
|
||||||
case kAlign:
|
case kAlign:
|
||||||
return WillAlign(aSelection, info->alignType, aCancel);
|
return WillAlign(aSelection, info->alignType, aCancel);
|
||||||
case kMakeHeader:
|
case kMakeBasicBlock:
|
||||||
return WillMakeHeader(aSelection, aCancel);
|
return WillMakeBasicBlock(aSelection, info->blockType, aCancel);
|
||||||
case kMakeAddress:
|
|
||||||
return WillMakeAddress(aSelection, aCancel);
|
|
||||||
case kMakePRE:
|
|
||||||
return WillMakePRE(aSelection, aCancel);
|
|
||||||
case kInsertElement:
|
case kInsertElement:
|
||||||
return WillInsert(aSelection, aCancel);
|
return WillInsert(aSelection, aCancel);
|
||||||
}
|
}
|
||||||
@ -258,7 +254,13 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel)
|
|||||||
return mEditor->InsertText(theString);
|
return mEditor->InsertText(theString);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMNode> blockParent = mEditor->GetBlockNodeParent(node);
|
nsCOMPtr<nsIDOMNode> blockParent;
|
||||||
|
|
||||||
|
if (nsEditor::IsBlockNode(node))
|
||||||
|
blockParent = node;
|
||||||
|
else
|
||||||
|
blockParent = mEditor->GetBlockNodeParent(node);
|
||||||
|
|
||||||
if (!blockParent) return NS_ERROR_FAILURE;
|
if (!blockParent) return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
// headers: put selection after the header
|
// headers: put selection after the header
|
||||||
@ -521,45 +523,18 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
|
|||||||
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
||||||
// initialize out param
|
// initialize out param
|
||||||
*aCancel = PR_FALSE;
|
*aCancel = PR_FALSE;
|
||||||
|
nsAutoString blockType("ul");
|
||||||
|
if (aOrdered) blockType = "ol";
|
||||||
|
|
||||||
nsAutoSelectionReset selectionResetter(aSelection);
|
nsAutoSelectionReset selectionResetter(aSelection);
|
||||||
nsresult res;
|
nsresult res;
|
||||||
|
|
||||||
// check for collapsed selection in empty block or after a <br>.
|
PRBool outMakeEmpty;
|
||||||
// Either way, we want to get the default behavior of creating
|
res = ShouldMakeEmptyBlock(aSelection, &blockType, &outMakeEmpty);
|
||||||
// an empty list.
|
|
||||||
|
|
||||||
PRBool isCollapsed;
|
|
||||||
res = aSelection->GetIsCollapsed(&isCollapsed);
|
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
if (isCollapsed)
|
if (outMakeEmpty) return NS_OK;
|
||||||
{
|
|
||||||
// is it after a <br>? Two possibilities: selection right after <br>;
|
|
||||||
// and selection at front of text node following <br>
|
|
||||||
nsCOMPtr<nsIDOMNode> parent, prevChild;
|
|
||||||
PRInt32 offset;
|
|
||||||
res = nsEditor::GetStartNodeAndOffset(aSelection, &parent, &offset);
|
|
||||||
if (nsEditor::IsTextNode(parent) && !offset)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIDOMNode> node = parent;
|
|
||||||
res = nsEditor::GetNodeLocation(node, &parent, &offset);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
}
|
|
||||||
if (offset)
|
|
||||||
{
|
|
||||||
prevChild = nsEditor::GetChildAt(parent, offset-1);
|
|
||||||
if (prevChild && IsBreak(prevChild))
|
|
||||||
return NS_OK; // insertion point after break
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise check for being in an empty block
|
|
||||||
PRBool isEmptyBlock;
|
|
||||||
res = IsEmptyBlock(parent, &isEmptyBlock);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
if (isEmptyBlock) return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ok, we aren't vreating a new empty list. Instead we are converting
|
// ok, we aren't creating a new empty list. Instead we are converting
|
||||||
// the set of blocks implied by the selection into a list.
|
// the set of blocks implied by the selection into a list.
|
||||||
|
|
||||||
// convert the selection ranges into "promoted" selection ranges:
|
// convert the selection ranges into "promoted" selection ranges:
|
||||||
@ -578,13 +553,6 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
|
|||||||
res = GetNodesForOperation(arrayOfRanges, &arrayOfNodes, kMakeList);
|
res = GetNodesForOperation(arrayOfRanges, &arrayOfNodes, kMakeList);
|
||||||
if (NS_FAILED(res)) return res;
|
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 from thinking about an array of
|
|
||||||
// nodes to act on to instead think of an array of ranges to act on.
|
|
||||||
|
|
||||||
// Remove all non-editable nodes. Leave them be.
|
// Remove all non-editable nodes. Leave them be.
|
||||||
|
|
||||||
PRUint32 listCount;
|
PRUint32 listCount;
|
||||||
@ -621,7 +589,7 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
|
|||||||
nsCOMPtr <nsIDOMNode> tmpNode = nsEditor::GetChildAt(curNode, 0);
|
nsCOMPtr <nsIDOMNode> tmpNode = nsEditor::GetChildAt(curNode, 0);
|
||||||
if (IsDiv(tmpNode) || IsOrderedList(tmpNode) || IsUnorderedList(tmpNode) || IsBlockquote(tmpNode))
|
if (IsDiv(tmpNode) || IsOrderedList(tmpNode) || IsUnorderedList(tmpNode) || IsBlockquote(tmpNode))
|
||||||
{
|
{
|
||||||
// check editablility XXX moose
|
// check editablility XXX floppy moose
|
||||||
curNode = tmpNode;
|
curNode = tmpNode;
|
||||||
}
|
}
|
||||||
else break;
|
else break;
|
||||||
@ -673,7 +641,6 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
|
|||||||
{
|
{
|
||||||
// make a new ordered list, insert it where the current unordered list is,
|
// make a new ordered list, insert it where the current unordered list is,
|
||||||
// and move all the children to the new list, and remove the old list
|
// and move all the children to the new list, and remove the old list
|
||||||
nsAutoString blockType("ol");
|
|
||||||
res = ReplaceContainer(curNode,&newBlock,blockType);
|
res = ReplaceContainer(curNode,&newBlock,blockType);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
curList = newBlock;
|
curList = newBlock;
|
||||||
@ -692,7 +659,6 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
|
|||||||
{
|
{
|
||||||
// make a new unordered list, insert it where the current ordered list is,
|
// make a new unordered list, insert it where the current ordered list is,
|
||||||
// and move all the children to the new list, and remove the old list
|
// and move all the children to the new list, and remove the old list
|
||||||
nsAutoString blockType("ul");
|
|
||||||
ReplaceContainer(curNode,&newBlock,blockType);
|
ReplaceContainer(curNode,&newBlock,blockType);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
curList = newBlock;
|
curList = newBlock;
|
||||||
@ -707,7 +673,7 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
|
|||||||
}
|
}
|
||||||
else if (IsDiv(curNode) || IsBlockquote(curNode))
|
else if (IsDiv(curNode) || IsBlockquote(curNode))
|
||||||
{
|
{
|
||||||
// XXX moose
|
// XXX floppy moose
|
||||||
}
|
}
|
||||||
} // lonely node
|
} // lonely node
|
||||||
|
|
||||||
@ -724,7 +690,7 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
|
|||||||
prevListItem = 0;
|
prevListItem = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if curNode is a Break, delete it, and quit remember prev list item
|
// if curNode is a Break, delete it, and quit remembering prev list item
|
||||||
if (IsBreak(curNode))
|
if (IsBreak(curNode))
|
||||||
{
|
{
|
||||||
res = mEditor->DeleteNode(curNode);
|
res = mEditor->DeleteNode(curNode);
|
||||||
@ -781,53 +747,35 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
|
|||||||
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsHTMLEditRules::WillMakeHeader(nsIDOMSelection *aSelection, PRBool *aCancel)
|
nsHTMLEditRules::WillMakeBasicBlock(nsIDOMSelection *aSelection, const nsString *aBlockType, PRBool *aCancel)
|
||||||
{
|
{
|
||||||
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
||||||
// initialize out param
|
// initialize out param
|
||||||
*aCancel = PR_TRUE;
|
*aCancel = PR_FALSE;
|
||||||
|
|
||||||
|
PRBool makeEmpty;
|
||||||
|
nsresult res = ShouldMakeEmptyBlock(aSelection, aBlockType, &makeEmpty);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
if (makeEmpty) return res; // just insert a new empty block
|
||||||
|
|
||||||
|
// else it's not that easy...
|
||||||
nsAutoSelectionReset selectionResetter(aSelection);
|
nsAutoSelectionReset selectionResetter(aSelection);
|
||||||
nsresult res;
|
*aCancel = PR_TRUE;
|
||||||
|
|
||||||
// Get the ranges for each break-delimited block
|
|
||||||
nsCOMPtr<nsIEnumerator> enumerator;
|
|
||||||
res = aSelection->GetEnumerator(getter_AddRefs(enumerator));
|
|
||||||
if (NS_SUCCEEDED(res) && enumerator)
|
|
||||||
{
|
|
||||||
for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next())
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsISupports> currentItem;
|
|
||||||
res = enumerator->CurrentItem(getter_AddRefs(currentItem));
|
|
||||||
if ((NS_SUCCEEDED(res)) && (currentItem))
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
|
|
||||||
PRBool isCollapsed;
|
|
||||||
range->GetIsCollapsed(&isCollapsed);
|
|
||||||
if (PR_FALSE==isCollapsed) // don't make headers out of empty ranges
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsISupportsArray> arrayOfRanges;
|
|
||||||
res = mEditor->GetBlockSectionsForRange(range, arrayOfRanges);
|
|
||||||
PRUint32 rangeCount;
|
|
||||||
res = arrayOfRanges->Count(&rangeCount);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
|
|
||||||
PRInt32 i;
|
|
||||||
nsCOMPtr<nsIDOMRange> opRange;
|
|
||||||
nsCOMPtr<nsISupports> isupports;
|
|
||||||
|
|
||||||
for (i = 0; i < rangeCount; i++)
|
nsCOMPtr<nsISupportsArray> arrayOfRanges;
|
||||||
{
|
res = GetPromotedRanges(aSelection, &arrayOfRanges, kMakeBasicBlock);
|
||||||
isupports = (dont_AddRef)(arrayOfRanges->ElementAt(i));
|
if (NS_FAILED(res)) return res;
|
||||||
opRange = do_QueryInterface(isupports);
|
|
||||||
// ConvertRangeToTag
|
// use these ranges to contruct a list of nodes to act on.
|
||||||
}
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
||||||
}
|
res = GetNodesForOperation(arrayOfRanges, &arrayOfNodes, kMakeBasicBlock);
|
||||||
}
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
|
||||||
}
|
// Ok, now go through all the nodes and make the right kind of blocks,
|
||||||
// unfinished, just return NS_OK for now
|
// or whatever is approriate. Wohoo!
|
||||||
return NS_OK;
|
res = ApplyBlockStyle(arrayOfNodes, aBlockType);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1015,15 +963,22 @@ nsHTMLEditRules::WillAlign(nsIDOMSelection *aSelection, const nsString *alignTyp
|
|||||||
{
|
{
|
||||||
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
||||||
// initialize out param
|
// initialize out param
|
||||||
*aCancel = PR_TRUE;
|
*aCancel = PR_FALSE;
|
||||||
|
|
||||||
nsAutoSelectionReset selectionResetter(aSelection);
|
nsAutoSelectionReset selectionResetter(aSelection);
|
||||||
nsresult res = NS_OK;
|
nsresult res = NS_OK;
|
||||||
|
|
||||||
|
PRBool outMakeEmpty;
|
||||||
|
res = ShouldMakeEmptyBlock(aSelection, alignType, &outMakeEmpty);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
if (outMakeEmpty) return NS_OK;
|
||||||
|
|
||||||
|
|
||||||
// convert the selection ranges into "promoted" selection ranges:
|
// convert the selection ranges into "promoted" selection ranges:
|
||||||
// this basically just expands the range to include the immediate
|
// this basically just expands the range to include the immediate
|
||||||
// block parent, and then further expands to include any ancestors
|
// block parent, and then further expands to include any ancestors
|
||||||
// whose children are all in the range
|
// whose children are all in the range
|
||||||
|
*aCancel = PR_TRUE;
|
||||||
|
|
||||||
nsCOMPtr<nsISupportsArray> arrayOfRanges;
|
nsCOMPtr<nsISupportsArray> arrayOfRanges;
|
||||||
res = GetPromotedRanges(aSelection, &arrayOfRanges, kAlign);
|
res = GetPromotedRanges(aSelection, &arrayOfRanges, kAlign);
|
||||||
@ -1100,32 +1055,6 @@ nsHTMLEditRules::WillAlign(nsIDOMSelection *aSelection, const nsString *alignTyp
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
nsHTMLEditRules::WillMakeAddress(nsIDOMSelection *aSelection, PRBool *aCancel)
|
|
||||||
{
|
|
||||||
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
|
||||||
// initialize out param
|
|
||||||
*aCancel = PR_FALSE;
|
|
||||||
|
|
||||||
nsresult res = NS_OK;
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
nsHTMLEditRules::WillMakePRE(nsIDOMSelection *aSelection, PRBool *aCancel)
|
|
||||||
{
|
|
||||||
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
|
||||||
// initialize out param
|
|
||||||
*aCancel = PR_FALSE;
|
|
||||||
|
|
||||||
nsresult res = NS_OK;
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/********************************************************
|
/********************************************************
|
||||||
* helper methods
|
* helper methods
|
||||||
********************************************************/
|
********************************************************/
|
||||||
@ -1186,6 +1115,24 @@ nsHTMLEditRules::IsListItem(nsIDOMNode *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// IsList: true if node an html list
|
||||||
|
//
|
||||||
|
PRBool
|
||||||
|
nsHTMLEditRules::IsList(nsIDOMNode *node)
|
||||||
|
{
|
||||||
|
NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsList");
|
||||||
|
nsAutoString tag;
|
||||||
|
nsEditor::GetTagString(node,tag);
|
||||||
|
if ( (tag == "ol") ||
|
||||||
|
(tag == "ul") )
|
||||||
|
{
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// IsOrderedList: true if node an html orderd list
|
// IsOrderedList: true if node an html orderd list
|
||||||
//
|
//
|
||||||
@ -1345,6 +1292,9 @@ nsHTMLEditRules::IsEmptyBlock(nsIDOMNode *aNode, PRBool *outIsEmptyBlock)
|
|||||||
}
|
}
|
||||||
else // an editable, non-text node. we aren't an empty block
|
else // an editable, non-text node. we aren't an empty block
|
||||||
{
|
{
|
||||||
|
// is it the node we are iterating over?
|
||||||
|
if (node.get() == aNode) break;
|
||||||
|
// otherwise it ain't empty
|
||||||
*outIsEmptyBlock = PR_FALSE;
|
*outIsEmptyBlock = PR_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1451,12 +1401,21 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt
|
|||||||
nsCOMPtr<nsIDOMNode> parent = aNode;
|
nsCOMPtr<nsIDOMNode> parent = aNode;
|
||||||
PRInt32 offset = aOffset;
|
PRInt32 offset = aOffset;
|
||||||
|
|
||||||
|
if (IsBody(aNode))
|
||||||
|
{
|
||||||
|
// we cant go any higher
|
||||||
|
*outNode = do_QueryInterface(aNode);
|
||||||
|
*outOffset = aOffset;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
if (aWhere == kStart)
|
if (aWhere == kStart)
|
||||||
{
|
{
|
||||||
// some special casing for text nodes
|
// some special casing for text nodes
|
||||||
if (nsEditor::IsTextNode(aNode))
|
if (nsEditor::IsTextNode(aNode))
|
||||||
{
|
{
|
||||||
nsEditor::GetNodeLocation(aNode, &parent, &offset);
|
res = nsEditor::GetNodeLocation(aNode, &parent, &offset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1464,26 +1423,38 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt
|
|||||||
if (!node) node = parent;
|
if (!node) node = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this is an inline node, back up through any prior inline nodes that
|
// if this is an inline node who's block parent is the body,
|
||||||
// aren't across a <br> from us, and that are enclosed in the same block.
|
// back up through any prior inline nodes that
|
||||||
|
// aren't across a <br> from us.
|
||||||
|
|
||||||
if (!nsEditor::IsBlockNode(node))
|
if (!nsEditor::IsBlockNode(node))
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIDOMNode> prevNode;
|
nsCOMPtr<nsIDOMNode> block = nsEditor::GetBlockNodeParent(node);
|
||||||
prevNode = nsEditor::NextNodeInBlock(node, nsEditor::kIterBackward);
|
if (IsBody(block))
|
||||||
while (prevNode)
|
|
||||||
{
|
{
|
||||||
if (IsBreak(prevNode))
|
nsCOMPtr<nsIDOMNode> prevNode;
|
||||||
break;
|
|
||||||
if (nsEditor::IsBlockNode(prevNode))
|
|
||||||
break;
|
|
||||||
node = prevNode;
|
|
||||||
prevNode = nsEditor::NextNodeInBlock(node, nsEditor::kIterBackward);
|
prevNode = nsEditor::NextNodeInBlock(node, nsEditor::kIterBackward);
|
||||||
|
while (prevNode)
|
||||||
|
{
|
||||||
|
if (IsBreak(prevNode))
|
||||||
|
break;
|
||||||
|
if (nsEditor::IsBlockNode(prevNode))
|
||||||
|
break;
|
||||||
|
node = prevNode;
|
||||||
|
prevNode = nsEditor::NextNodeInBlock(node, nsEditor::kIterBackward);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// just grap the whole block
|
||||||
|
node = block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// finding the real start for this point. look up the tree for as long as we are the
|
// finding the real start for this point. look up the tree for as long as we are the
|
||||||
// first node in the container, and as long as we haven't hit the body node.
|
// first node in the container, and as long as we haven't hit the body node.
|
||||||
|
nsEditor::GetNodeLocation(node, &parent, &offset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
while ((IsFirstNode(node)) && (!IsBody(parent)))
|
while ((IsFirstNode(node)) && (!IsBody(parent)))
|
||||||
{
|
{
|
||||||
node = parent;
|
node = parent;
|
||||||
@ -1508,39 +1479,49 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt
|
|||||||
if (!node) node = parent;
|
if (!node) node = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node)
|
if (!node)
|
||||||
offset++; // since this is going to be used for a range _endpoint_, we want to be after the node
|
|
||||||
else
|
|
||||||
node = parent;
|
node = parent;
|
||||||
|
|
||||||
// if this is an inline node, look ahead through any further inline nodes that
|
// if this is an inline node who's block parent is the body,
|
||||||
|
// look ahead through any further inline nodes that
|
||||||
// aren't across a <br> from us, and that are enclosed in the same block.
|
// aren't across a <br> from us, and that are enclosed in the same block.
|
||||||
|
|
||||||
if (!nsEditor::IsBlockNode(node))
|
if (!nsEditor::IsBlockNode(node))
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIDOMNode> nextNode;
|
nsCOMPtr<nsIDOMNode> block = nsEditor::GetBlockNodeParent(node);
|
||||||
nextNode = nsEditor::NextNodeInBlock(node, nsEditor::kIterForward);
|
if (IsBody(block))
|
||||||
while (nextNode)
|
|
||||||
{
|
{
|
||||||
if (IsBreak(nextNode))
|
nsCOMPtr<nsIDOMNode> nextNode;
|
||||||
break;
|
|
||||||
if (nsEditor::IsBlockNode(nextNode))
|
|
||||||
break;
|
|
||||||
node = nextNode;
|
|
||||||
nextNode = nsEditor::NextNodeInBlock(node, nsEditor::kIterForward);
|
nextNode = nsEditor::NextNodeInBlock(node, nsEditor::kIterForward);
|
||||||
|
while (nextNode)
|
||||||
|
{
|
||||||
|
if (IsBreak(nextNode))
|
||||||
|
break;
|
||||||
|
if (nsEditor::IsBlockNode(nextNode))
|
||||||
|
break;
|
||||||
|
node = nextNode;
|
||||||
|
nextNode = nsEditor::NextNodeInBlock(node, nsEditor::kIterForward);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// just grap the whole block
|
||||||
|
node = block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// finding the real end for this point. look up the tree for as long as we are the
|
// finding the real end for this point. look up the tree for as long as we are the
|
||||||
// last node in the container, and as long as we haven't hit the body node.
|
// last node in the container, and as long as we haven't hit the body node.
|
||||||
|
nsEditor::GetNodeLocation(node, &parent, &offset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
while ((IsLastNode(node)) && (!IsBody(parent)))
|
while ((IsLastNode(node)) && (!IsBody(parent)))
|
||||||
{
|
{
|
||||||
node = parent;
|
node = parent;
|
||||||
res = nsEditor::GetNodeLocation(node, &parent, &offset);
|
res = nsEditor::GetNodeLocation(node, &parent, &offset);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
offset++;
|
|
||||||
}
|
}
|
||||||
*outNode = parent;
|
*outNode = parent;
|
||||||
|
offset++; // add one since this in an endpoint - want to be AFTER node.
|
||||||
*outOffset = offset;
|
*outOffset = offset;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -1669,6 +1650,41 @@ nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// GetChildNodesForOperation:
|
||||||
|
//
|
||||||
|
nsresult
|
||||||
|
nsHTMLEditRules::GetChildNodesForOperation(nsIDOMNode *inNode,
|
||||||
|
nsCOMPtr<nsISupportsArray> *outArrayOfNodes)
|
||||||
|
{
|
||||||
|
if (!inNode || !outArrayOfNodes) return NS_ERROR_NULL_POINTER;
|
||||||
|
|
||||||
|
nsresult res = NS_NewISupportsArray(getter_AddRefs(*outArrayOfNodes));
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMNodeList> childNodes;
|
||||||
|
res = inNode->GetChildNodes(getter_AddRefs(childNodes));
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
PRUint32 childCount;
|
||||||
|
res = childNodes->GetLength(&childCount);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
PRUint32 i;
|
||||||
|
nsCOMPtr<nsIDOMNode> node;
|
||||||
|
nsCOMPtr<nsISupports> isupports;
|
||||||
|
for (i = 0; i < childCount; i++)
|
||||||
|
{
|
||||||
|
res = childNodes->Item( i, getter_AddRefs(node));
|
||||||
|
if (!node) return NS_ERROR_FAILURE;
|
||||||
|
isupports = do_QueryInterface(node);
|
||||||
|
(*outArrayOfNodes)->AppendElement(isupports);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// MakeTransitionList: detect all the transitions in the array, where a
|
// MakeTransitionList: detect all the transitions in the array, where a
|
||||||
// transition means that adjacent nodes in the array
|
// transition means that adjacent nodes in the array
|
||||||
@ -1716,7 +1732,7 @@ nsHTMLEditRules::MakeTransitionList(nsISupportsArray *inArrayOfNodes,
|
|||||||
nsresult
|
nsresult
|
||||||
nsHTMLEditRules::ReplaceContainer(nsIDOMNode *inNode,
|
nsHTMLEditRules::ReplaceContainer(nsIDOMNode *inNode,
|
||||||
nsCOMPtr<nsIDOMNode> *outNode,
|
nsCOMPtr<nsIDOMNode> *outNode,
|
||||||
nsString &aNodeType)
|
const nsString &aNodeType)
|
||||||
{
|
{
|
||||||
if (!inNode || !outNode)
|
if (!inNode || !outNode)
|
||||||
return NS_ERROR_NULL_POINTER;
|
return NS_ERROR_NULL_POINTER;
|
||||||
@ -1733,13 +1749,12 @@ nsHTMLEditRules::ReplaceContainer(nsIDOMNode *inNode,
|
|||||||
offset = 0;
|
offset = 0;
|
||||||
while (bHasMoreChildren)
|
while (bHasMoreChildren)
|
||||||
{
|
{
|
||||||
inNode->GetFirstChild(getter_AddRefs(child));
|
inNode->GetLastChild(getter_AddRefs(child));
|
||||||
res = mEditor->DeleteNode(child);
|
res = mEditor->DeleteNode(child);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
res = mEditor->InsertNode(child, *outNode, offset);
|
res = mEditor->InsertNode(child, *outNode, 0);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
inNode->HasChildNodes(&bHasMoreChildren);
|
inNode->HasChildNodes(&bHasMoreChildren);
|
||||||
offset++;
|
|
||||||
}
|
}
|
||||||
res = mEditor->DeleteNode(inNode);
|
res = mEditor->DeleteNode(inNode);
|
||||||
return res;
|
return res;
|
||||||
@ -1952,42 +1967,43 @@ nsHTMLEditRules::InsertSpace(nsIDOMSelection *aSelection,
|
|||||||
nsresult
|
nsresult
|
||||||
nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection,
|
nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection,
|
||||||
nsIDOMNode *aHeader,
|
nsIDOMNode *aHeader,
|
||||||
nsIDOMNode *aTextNode,
|
nsIDOMNode *aNode,
|
||||||
PRInt32 aOffset)
|
PRInt32 aOffset)
|
||||||
{
|
{
|
||||||
if (!aSelection || !aHeader || !aTextNode) return NS_ERROR_NULL_POINTER;
|
if (!aSelection || !aHeader || !aNode) return NS_ERROR_NULL_POINTER;
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMNode> leftNode;
|
// remeber where the header is
|
||||||
nsCOMPtr<nsIDOMNode> textNode = do_QueryInterface(aTextNode); // to hold a ref across the delete call
|
nsCOMPtr<nsIDOMNode> headerParent;
|
||||||
// split the node
|
PRInt32 offset;
|
||||||
nsresult res = mEditor->SplitNode(aTextNode, aOffset, getter_AddRefs(leftNode));
|
nsresult res = nsEditor::GetNodeLocation(aHeader, &headerParent, &offset);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
// move the right node outside of the header, via deletion/insertion
|
|
||||||
// delete the right node
|
|
||||||
res = mEditor->DeleteNode(textNode);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
|
|
||||||
// insert the right node
|
|
||||||
nsCOMPtr<nsIDOMNode> p;
|
|
||||||
aHeader->GetParentNode(getter_AddRefs(p));
|
|
||||||
PRInt32 indx = mEditor->GetIndexOf(p,aHeader);
|
|
||||||
res = mEditor->InsertNode(textNode,p,indx+1);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
|
|
||||||
// merge text node with like sibling, if any
|
|
||||||
nsCOMPtr<nsIDOMNode> sibling;
|
|
||||||
textNode->GetNextSibling(getter_AddRefs(sibling));
|
|
||||||
if (sibling && mEditor->IsTextNode(sibling) && mEditor->IsEditable(sibling))
|
|
||||||
{
|
|
||||||
res = mEditor->JoinNodes(textNode,sibling,p);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
textNode = sibling; // sibling was the node kept by the join; remember it in "textNode"
|
|
||||||
}
|
|
||||||
|
|
||||||
// position selection before inserted node
|
|
||||||
res = aSelection->Collapse(textNode,0);
|
|
||||||
|
|
||||||
|
// split the header
|
||||||
|
PRInt32 newOffset;
|
||||||
|
res = mEditor->SplitNodeDeep( aHeader, aNode, aOffset, &newOffset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
// revisit the below when we move to using divs as standard paragraphs.
|
||||||
|
// need to create an "empty" div in the fisrt case below, and need to
|
||||||
|
// use a div instead of a <p> in the second case below
|
||||||
|
|
||||||
|
// if the new (righthand) header node is empty, delete it
|
||||||
|
PRBool isEmpty;
|
||||||
|
res = IsEmptyBlock(aHeader, &isEmpty);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
if (isEmpty)
|
||||||
|
{
|
||||||
|
res = mEditor->DeleteNode(aHeader);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = aSelection->Collapse(headerParent,offset+1);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
// else rewrap it in a paragraph
|
||||||
|
nsCOMPtr<nsIDOMNode> newBlock;
|
||||||
|
nsAutoString blockType("p");
|
||||||
|
res = ReplaceContainer(aHeader,&newBlock,blockType);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = aSelection->Collapse(newBlock,0);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2097,12 +2113,282 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,
|
|||||||
PRInt32 aOffset)
|
PRInt32 aOffset)
|
||||||
{
|
{
|
||||||
if (!aSelection || !aListItem || !aNode) return NS_ERROR_NULL_POINTER;
|
if (!aSelection || !aListItem || !aNode) return NS_ERROR_NULL_POINTER;
|
||||||
|
nsresult res = NS_OK;
|
||||||
PRInt32 newOffset;
|
|
||||||
nsresult res = mEditor->SplitNodeDeep( aListItem, aNode, aOffset, &newOffset);
|
nsCOMPtr<nsIDOMNode> listitem;
|
||||||
|
|
||||||
|
// sanity check
|
||||||
|
NS_PRECONDITION(PR_TRUE == IsListItem(aListItem), "expected a list item and didnt get one");
|
||||||
|
|
||||||
|
// if we are in an empty listitem, then we want to pop up out of the list
|
||||||
|
PRBool isEmpty;
|
||||||
|
res = IsEmptyBlock(aListItem, &isEmpty);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
res = aSelection->Collapse(aNode,0);
|
if (isEmpty)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIDOMNode> list, listparent;
|
||||||
|
PRInt32 offset;
|
||||||
|
list = nsEditor::GetBlockNodeParent(aListItem);
|
||||||
|
res = nsEditor::GetNodeLocation(list, &listparent, &offset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
// are we in a sublist?
|
||||||
|
if (IsList(listparent)) //in a sublist
|
||||||
|
{
|
||||||
|
// if so, move this list item out of this list and into the grandparent list
|
||||||
|
res = mEditor->DeleteNode(aListItem);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = mEditor->InsertNode(aListItem,listparent,offset+1);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = aSelection->Collapse(aListItem,0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// otherwise kill this listitem and set the selection to after the parent list
|
||||||
|
res = mEditor->DeleteNode(aListItem);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = aSelection->Collapse(listparent,offset+1);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// else we want a new list item at the same list level
|
||||||
|
PRInt32 newOffset;
|
||||||
|
res = mEditor->SplitNodeDeep( aListItem, aNode, aOffset, &newOffset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = aSelection->Collapse(aListItem,0);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// ShouldMakeEmptyBlock: determine if a block transformation should make
|
||||||
|
// a new empty block, or instead transform a block
|
||||||
|
//
|
||||||
|
nsresult
|
||||||
|
nsHTMLEditRules::ShouldMakeEmptyBlock(nsIDOMSelection *aSelection,
|
||||||
|
const nsString *blockTag,
|
||||||
|
PRBool *outMakeEmpty)
|
||||||
|
{
|
||||||
|
// a note about strategy:
|
||||||
|
// this routine will be called by the rules code to figure out
|
||||||
|
// if it should do something, or let the nsHTMLEditor default
|
||||||
|
// action happen. The default action is to insert a new block.
|
||||||
|
// Note that if _nothing_ should happen, ie, the selection is
|
||||||
|
// already entireyl inside a block (or blocks) or the correct type,
|
||||||
|
// then you don't want to return true in outMakeEmpty, since the
|
||||||
|
// defualt code will insert a new empty block anyway, rather than
|
||||||
|
// doing nothing. So we have to detect that case and return false.
|
||||||
|
|
||||||
|
if (!aSelection || !outMakeEmpty) return NS_ERROR_NULL_POINTER;
|
||||||
|
nsresult res = NS_OK;
|
||||||
|
|
||||||
|
// if the selection is collapsed, and
|
||||||
|
// if we in the body, or after a <br> with
|
||||||
|
// no more inline content before the next block, then we want
|
||||||
|
// a new block. Otherwise we want to trasform a block
|
||||||
|
|
||||||
|
// xxx possible bug: selection could be not callapsed, but
|
||||||
|
// still empty. it would be nice to have a call for this: IsEmptySelection()
|
||||||
|
|
||||||
|
PRBool isCollapsed;
|
||||||
|
res = aSelection->GetIsCollapsed(&isCollapsed);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
if (isCollapsed)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIDOMNode> parent;
|
||||||
|
PRInt32 offset;
|
||||||
|
res = nsEditor::GetStartNodeAndOffset(aSelection, &parent, &offset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
// is selection point in the body?
|
||||||
|
if (IsBody(parent))
|
||||||
|
{
|
||||||
|
*outMakeEmpty = PR_TRUE;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if block parent is already right kind of block.
|
||||||
|
// See strategy comment above.
|
||||||
|
nsCOMPtr<nsIDOMNode> block;
|
||||||
|
if (!nsEditor::IsBlockNode(parent))
|
||||||
|
block = nsEditor::GetBlockNodeParent(parent);
|
||||||
|
else
|
||||||
|
block = parent;
|
||||||
|
if (block)
|
||||||
|
{
|
||||||
|
nsAutoString tag;
|
||||||
|
nsEditor::GetTagString(block,tag);
|
||||||
|
if (tag == *blockTag)
|
||||||
|
{
|
||||||
|
*outMakeEmpty = PR_FALSE;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// are we in a textnode or inline node?
|
||||||
|
if (!nsEditor::IsBlockNode(parent))
|
||||||
|
{
|
||||||
|
// we must be in a text or inline node - convert existing block
|
||||||
|
*outMakeEmpty = PR_FALSE;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// is it after a <br> with no inline nodes after it, or a <br> after it??
|
||||||
|
if (offset)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIDOMNode> prevChild, nextChild, tmp;
|
||||||
|
prevChild = nsEditor::GetChildAt(parent, offset-1);
|
||||||
|
while (prevChild && !mEditor->IsEditable(prevChild))
|
||||||
|
{
|
||||||
|
// search back until we either find an editable node,
|
||||||
|
// or hit the beginning of the block
|
||||||
|
tmp = nsEditor::NextNodeInBlock(prevChild, nsEditor::kIterBackward);
|
||||||
|
prevChild = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevChild && IsBreak(prevChild))
|
||||||
|
{
|
||||||
|
nextChild = nsEditor::GetChildAt(parent, offset);
|
||||||
|
while (nextChild && !mEditor->IsEditable(nextChild))
|
||||||
|
{
|
||||||
|
// search back until we either find an editable node,
|
||||||
|
// or hit the beginning of the block
|
||||||
|
tmp = nsEditor::NextNodeInBlock(nextChild, nsEditor::kIterForward);
|
||||||
|
nextChild = tmp;
|
||||||
|
}
|
||||||
|
if (!nextChild || IsBreak(nextChild) || nsEditor::IsBlockNode(nextChild))
|
||||||
|
{
|
||||||
|
// we are after a <br> and not before inline content,
|
||||||
|
// or we are between <br>s.
|
||||||
|
// make an empty block
|
||||||
|
*outMakeEmpty = PR_FALSE;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// otherwise transform an existing block
|
||||||
|
*outMakeEmpty = PR_FALSE;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// ApplyBlockStyle: do whatever it takes to make the list of nodes into
|
||||||
|
// one or more blocks of type blockTag.
|
||||||
|
//
|
||||||
|
nsresult
|
||||||
|
nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString *aBlockTag)
|
||||||
|
{
|
||||||
|
// intent of this routine is to be used for converting to/from
|
||||||
|
// headers, paragraphs (or moz-divs), pre, and address. Those blocks
|
||||||
|
// that pretty much just contain inline things...
|
||||||
|
|
||||||
|
if (!arrayOfNodes || !aBlockTag) return NS_ERROR_NULL_POINTER;
|
||||||
|
nsresult res = NS_OK;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMNode> curNode, curParent, curBlock, newBlock;
|
||||||
|
PRInt32 offset;
|
||||||
|
PRUint32 listCount;
|
||||||
|
arrayOfNodes->Count(&listCount);
|
||||||
|
|
||||||
|
PRUint32 i;
|
||||||
|
for (i=0; i<listCount; i++)
|
||||||
|
{
|
||||||
|
// get the node to act on, and it's location
|
||||||
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
||||||
|
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
|
||||||
|
res = nsEditor::GetNodeLocation(curNode, &curParent, &offset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
nsAutoString curNodeTag;
|
||||||
|
nsEditor::GetTagString(curNode, curNodeTag);
|
||||||
|
|
||||||
|
|
||||||
|
// is it already the right kind of block?
|
||||||
|
if (curNodeTag == *aBlockTag)
|
||||||
|
{
|
||||||
|
curBlock = 0; // forget any previous block used for previous inline nodes
|
||||||
|
continue; // do nothing to this block
|
||||||
|
}
|
||||||
|
|
||||||
|
// if curNode is a <pre> and we are converting to non-pre, we need
|
||||||
|
// to process the text inside the <pre> so as to convert returns
|
||||||
|
// to breaks, and runs of spaces to nbsps.
|
||||||
|
// xxx floppy moose
|
||||||
|
|
||||||
|
// if curNode is a p, header, address, or pre, replace
|
||||||
|
// it with a new block of correct type.
|
||||||
|
// xxx floppy moose: pre cant hold everything the others can
|
||||||
|
if ((curNodeTag == "pre") ||
|
||||||
|
(curNodeTag == "p") ||
|
||||||
|
(curNodeTag == "h1") ||
|
||||||
|
(curNodeTag == "h2") ||
|
||||||
|
(curNodeTag == "h3") ||
|
||||||
|
(curNodeTag == "h4") ||
|
||||||
|
(curNodeTag == "h5") ||
|
||||||
|
(curNodeTag == "h6") ||
|
||||||
|
(curNodeTag == "address"))
|
||||||
|
{
|
||||||
|
curBlock = 0; // forget any previous block used for previous inline nodes
|
||||||
|
res = ReplaceContainer(curNode, &newBlock, *aBlockTag);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
}
|
||||||
|
else if ((curNodeTag == "table") ||
|
||||||
|
(curNodeTag == "tbody") ||
|
||||||
|
(curNodeTag == "tr") ||
|
||||||
|
(curNodeTag == "td") ||
|
||||||
|
(curNodeTag == "ol") ||
|
||||||
|
(curNodeTag == "ul") ||
|
||||||
|
(curNodeTag == "li") ||
|
||||||
|
(curNodeTag == "blockquote") ||
|
||||||
|
(curNodeTag == "div"))
|
||||||
|
{
|
||||||
|
curBlock = 0; // forget any previous block used for previous inline nodes
|
||||||
|
// recursion time
|
||||||
|
nsCOMPtr<nsISupportsArray> childArray;
|
||||||
|
res = GetChildNodesForOperation(curNode, &childArray);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = ApplyBlockStyle(childArray, aBlockTag);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if curNode is inline, pull it into curBlock
|
||||||
|
// note: it's assumed that consecutive inline nodes in the
|
||||||
|
// arrayOfNodes are actually members of the same block parent.
|
||||||
|
// this happens to be true now as a side effect of how
|
||||||
|
// arrayOfNodes is contructed, but some additional logic should
|
||||||
|
// be added here if that should change
|
||||||
|
|
||||||
|
else if (nsEditor::IsInlineNode(curNode))
|
||||||
|
{
|
||||||
|
// if curNode is a non editable, drop it if we are going to <pre>
|
||||||
|
if ((*aBlockTag == "pre") && (!mEditor->IsEditable(curNode)))
|
||||||
|
continue; // do nothing to this block
|
||||||
|
|
||||||
|
// if no curBlock, make one
|
||||||
|
if (!curBlock)
|
||||||
|
{
|
||||||
|
res = mEditor->CreateNode(*aBlockTag, curParent, offset, getter_AddRefs(curBlock));
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if curNode is a Break, replace it with a return if we are going to <pre>
|
||||||
|
// xxx floppy moose
|
||||||
|
|
||||||
|
// this is a continuation of some inline nodes that belong together in
|
||||||
|
// the same block item. use curBlock
|
||||||
|
PRUint32 blockLen;
|
||||||
|
res = mEditor->GetLengthOfDOMNode(curBlock, blockLen);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = mEditor->DeleteNode(curNode);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = mEditor->InsertNode(curNode, curBlock, blockLen);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,12 +39,6 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
enum IterDirection
|
|
||||||
{
|
|
||||||
kIterForward,
|
|
||||||
kIterBackward
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RulesEndpoint
|
enum RulesEndpoint
|
||||||
{
|
{
|
||||||
kStart,
|
kStart,
|
||||||
@ -66,9 +60,7 @@ protected:
|
|||||||
nsresult WillIndent(nsIDOMSelection *aSelection, PRBool *aCancel);
|
nsresult WillIndent(nsIDOMSelection *aSelection, PRBool *aCancel);
|
||||||
nsresult WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel);
|
nsresult WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel);
|
||||||
nsresult WillAlign(nsIDOMSelection *aSelection, const nsString *alignType, PRBool *aCancel);
|
nsresult WillAlign(nsIDOMSelection *aSelection, const nsString *alignType, PRBool *aCancel);
|
||||||
nsresult WillMakeHeader(nsIDOMSelection *aSelection, PRBool *aCancel);
|
nsresult WillMakeBasicBlock(nsIDOMSelection *aSelection, const nsString *aBlockType, PRBool *aCancel);
|
||||||
nsresult WillMakeAddress(nsIDOMSelection *aSelection, PRBool *aCancel);
|
|
||||||
nsresult WillMakePRE(nsIDOMSelection *aSelection, PRBool *aCancel);
|
|
||||||
|
|
||||||
nsresult InsertTab(nsIDOMSelection *aSelection, PRBool *aCancel, PlaceholderTxn **aTxn, nsString *outString);
|
nsresult InsertTab(nsIDOMSelection *aSelection, PRBool *aCancel, PlaceholderTxn **aTxn, nsString *outString);
|
||||||
nsresult InsertSpace(nsIDOMSelection *aSelection, PRBool *aCancel, PlaceholderTxn **aTxn, nsString *outString);
|
nsresult InsertSpace(nsIDOMSelection *aSelection, PRBool *aCancel, PlaceholderTxn **aTxn, nsString *outString);
|
||||||
@ -84,6 +76,7 @@ protected:
|
|||||||
static PRBool IsHeader(nsIDOMNode *aNode);
|
static PRBool IsHeader(nsIDOMNode *aNode);
|
||||||
static PRBool IsParagraph(nsIDOMNode *aNode);
|
static PRBool IsParagraph(nsIDOMNode *aNode);
|
||||||
static PRBool IsListItem(nsIDOMNode *aNode);
|
static PRBool IsListItem(nsIDOMNode *aNode);
|
||||||
|
static PRBool IsList(nsIDOMNode *aNode);
|
||||||
static PRBool IsUnorderedList(nsIDOMNode *aNode);
|
static PRBool IsUnorderedList(nsIDOMNode *aNode);
|
||||||
static PRBool IsOrderedList(nsIDOMNode *aNode);
|
static PRBool IsOrderedList(nsIDOMNode *aNode);
|
||||||
static PRBool IsBreak(nsIDOMNode *aNode);
|
static PRBool IsBreak(nsIDOMNode *aNode);
|
||||||
@ -94,19 +87,24 @@ protected:
|
|||||||
nsresult IsEmptyBlock(nsIDOMNode *aNode, PRBool *outIsEmptyBlock);
|
nsresult IsEmptyBlock(nsIDOMNode *aNode, PRBool *outIsEmptyBlock);
|
||||||
PRBool IsFirstNode(nsIDOMNode *aNode);
|
PRBool IsFirstNode(nsIDOMNode *aNode);
|
||||||
PRBool IsLastNode(nsIDOMNode *aNode);
|
PRBool IsLastNode(nsIDOMNode *aNode);
|
||||||
|
|
||||||
nsresult GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt32 aOffset,
|
nsresult GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt32 aOffset,
|
||||||
PRInt32 actionID, nsCOMPtr<nsIDOMNode> *outNode, PRInt32 *outOffset);
|
PRInt32 actionID, nsCOMPtr<nsIDOMNode> *outNode, PRInt32 *outOffset);
|
||||||
|
|
||||||
nsresult GetPromotedRanges(nsIDOMSelection *inSelection,
|
nsresult GetPromotedRanges(nsIDOMSelection *inSelection,
|
||||||
nsCOMPtr<nsISupportsArray> *outArrayOfRanges,
|
nsCOMPtr<nsISupportsArray> *outArrayOfRanges,
|
||||||
PRInt32 inOperationType);
|
PRInt32 inOperationType);
|
||||||
static nsresult GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
|
nsresult GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
|
||||||
nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
||||||
PRInt32 inOperationType);
|
PRInt32 inOperationType);
|
||||||
static nsresult MakeTransitionList(nsISupportsArray *inArrayOfNodes,
|
nsresult GetChildNodesForOperation(nsIDOMNode *inNode,
|
||||||
|
nsCOMPtr<nsISupportsArray> *outArrayOfNodes);
|
||||||
|
nsresult MakeTransitionList(nsISupportsArray *inArrayOfNodes,
|
||||||
nsVoidArray *inTransitionArray);
|
nsVoidArray *inTransitionArray);
|
||||||
|
|
||||||
nsresult ReplaceContainer(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, nsString &aNodeType);
|
nsresult ShouldMakeEmptyBlock(nsIDOMSelection *aSelection, const nsString *blockTag, PRBool *outMakeEmpty);
|
||||||
|
nsresult ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString *aBlockTag);
|
||||||
|
|
||||||
|
nsresult ReplaceContainer(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, const nsString &aNodeType);
|
||||||
nsresult RemoveContainer(nsIDOMNode *inNode);
|
nsresult RemoveContainer(nsIDOMNode *inNode);
|
||||||
nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, nsString &aNodeType);
|
nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, nsString &aNodeType);
|
||||||
|
|
||||||
|
@ -1317,14 +1317,17 @@ NS_IMETHODIMP nsHTMLEditor::SetParagraphFormat(const nsString& aParagraphFormat)
|
|||||||
//Kinda sad to waste memory just to force lower case
|
//Kinda sad to waste memory just to force lower case
|
||||||
nsAutoString tag = aParagraphFormat;
|
nsAutoString tag = aParagraphFormat;
|
||||||
tag.ToLowerCase();
|
tag.ToLowerCase();
|
||||||
if (tag == "normal" || tag == "p") {
|
if (tag == "normal")
|
||||||
res = RemoveParagraphStyle();
|
{
|
||||||
} else if (tag == "li") {
|
res = InsertBasicBlock("p");
|
||||||
|
}
|
||||||
|
else if (tag == "li")
|
||||||
|
{
|
||||||
res = InsertList("ul");
|
res = InsertList("ul");
|
||||||
} else if (tag[0] == 'h') {
|
}
|
||||||
res = InsertHeader(tag);
|
else
|
||||||
} else {
|
{
|
||||||
res = ReplaceBlockParent(tag);
|
res = InsertBasicBlock(tag);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -1646,6 +1649,7 @@ nsHTMLEditor::InsertList(const nsString& aListType)
|
|||||||
// XXX - revisit when layout is fixed
|
// XXX - revisit when layout is fixed
|
||||||
res = selection->Collapse(newItem,0);
|
res = selection->Collapse(newItem,0);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
#if 0
|
||||||
nsAutoString theText(" ");
|
nsAutoString theText(" ");
|
||||||
res = InsertText(theText);
|
res = InsertText(theText);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
@ -1654,6 +1658,7 @@ nsHTMLEditor::InsertList(const nsString& aListType)
|
|||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
res = selection->Collapse(node,0);
|
res = selection->Collapse(node,0);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -1661,13 +1666,13 @@ nsHTMLEditor::InsertList(const nsString& aListType)
|
|||||||
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsHTMLEditor::InsertHeader(const nsString& aHeaderType)
|
nsHTMLEditor::InsertBasicBlock(const nsString& aBlockType)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_JS_EDITOR_LOG
|
#ifdef ENABLE_JS_EDITOR_LOG
|
||||||
nsAutoJSEditorLogLock logLock(mJSEditorLog);
|
nsAutoJSEditorLogLock logLock(mJSEditorLog);
|
||||||
|
|
||||||
if (mJSEditorLog)
|
if (mJSEditorLog)
|
||||||
mJSEditorLog->InsertHeader(aHeaderType);
|
mJSEditorLog->InsertBasicBlock(aBlockType);
|
||||||
#endif // ENABLE_JS_EDITOR_LOG
|
#endif // ENABLE_JS_EDITOR_LOG
|
||||||
|
|
||||||
nsresult res;
|
nsresult res;
|
||||||
@ -1680,7 +1685,8 @@ nsHTMLEditor::InsertHeader(const nsString& aHeaderType)
|
|||||||
|
|
||||||
// pre-process
|
// pre-process
|
||||||
nsEditor::GetSelection(getter_AddRefs(selection));
|
nsEditor::GetSelection(getter_AddRefs(selection));
|
||||||
nsTextRulesInfo ruleInfo(nsHTMLEditRules::kMakeHeader);
|
nsTextRulesInfo ruleInfo(nsHTMLEditRules::kMakeBasicBlock);
|
||||||
|
ruleInfo.blockType = &aBlockType;
|
||||||
res = mRules->WillDoAction(selection, &ruleInfo, &cancel);
|
res = mRules->WillDoAction(selection, &ruleInfo, &cancel);
|
||||||
if (cancel || (NS_FAILED(res))) return res;
|
if (cancel || (NS_FAILED(res))) return res;
|
||||||
|
|
||||||
@ -1700,12 +1706,12 @@ nsHTMLEditor::InsertHeader(const nsString& aHeaderType)
|
|||||||
|
|
||||||
if (isCollapsed)
|
if (isCollapsed)
|
||||||
{
|
{
|
||||||
// have to find a place to put the header
|
// have to find a place to put the block
|
||||||
nsCOMPtr<nsIDOMNode> parent = node;
|
nsCOMPtr<nsIDOMNode> parent = node;
|
||||||
nsCOMPtr<nsIDOMNode> topChild = node;
|
nsCOMPtr<nsIDOMNode> topChild = node;
|
||||||
nsCOMPtr<nsIDOMNode> tmp;
|
nsCOMPtr<nsIDOMNode> tmp;
|
||||||
|
|
||||||
while ( !CanContainTag(parent, aHeaderType))
|
while ( !CanContainTag(parent, aBlockType))
|
||||||
{
|
{
|
||||||
parent->GetParentNode(getter_AddRefs(tmp));
|
parent->GetParentNode(getter_AddRefs(tmp));
|
||||||
if (!tmp) return NS_ERROR_FAILURE;
|
if (!tmp) return NS_ERROR_FAILURE;
|
||||||
@ -1720,9 +1726,23 @@ nsHTMLEditor::InsertHeader(const nsString& aHeaderType)
|
|||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make a header
|
// make a block
|
||||||
nsCOMPtr<nsIDOMNode> newHeader;
|
nsCOMPtr<nsIDOMNode> newBlock;
|
||||||
res = CreateNode(aHeaderType, parent, offset, getter_AddRefs(newHeader));
|
res = CreateNode(aBlockType, parent, offset, getter_AddRefs(newBlock));
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
// xxx
|
||||||
|
|
||||||
|
// put a space in it so layout will draw it
|
||||||
|
res = selection->Collapse(newBlock,0);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
nsAutoString theText(nbsp);
|
||||||
|
res = InsertText(theText);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
// reposition selection to before the space character
|
||||||
|
res = GetStartNodeAndOffset(selection, &node, &offset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = selection->Collapse(node,0);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ public:
|
|||||||
NS_IMETHOD RemoveParent(const nsString &aParentTag);
|
NS_IMETHOD RemoveParent(const nsString &aParentTag);
|
||||||
|
|
||||||
NS_IMETHOD InsertList(const nsString& aListType);
|
NS_IMETHOD InsertList(const nsString& aListType);
|
||||||
NS_IMETHOD InsertHeader(const nsString& aHeaderType);
|
NS_IMETHOD InsertBasicBlock(const nsString& aBlockType);
|
||||||
NS_IMETHOD Indent(const nsString& aIndent);
|
NS_IMETHOD Indent(const nsString& aIndent);
|
||||||
NS_IMETHOD Align(const nsString& aAlign);
|
NS_IMETHOD Align(const nsString& aAlign);
|
||||||
|
|
||||||
|
@ -73,9 +73,7 @@ public:
|
|||||||
kIndent = 3002,
|
kIndent = 3002,
|
||||||
kOutdent = 3003,
|
kOutdent = 3003,
|
||||||
kAlign = 3004,
|
kAlign = 3004,
|
||||||
kMakeHeader = 3005,
|
kMakeBasicBlock = 3005,
|
||||||
kMakeAddress = 3006,
|
|
||||||
kMakePRE = 3007,
|
|
||||||
kInsertElement = 3008
|
kInsertElement = 3008
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -179,6 +177,7 @@ class nsTextRulesInfo : public nsRulesInfo
|
|||||||
collapsedAction(nsIEditor::eDeleteNext),
|
collapsedAction(nsIEditor::eDeleteNext),
|
||||||
bOrdered(PR_FALSE),
|
bOrdered(PR_FALSE),
|
||||||
alignType(0),
|
alignType(0),
|
||||||
|
blockType(0),
|
||||||
insertElement(0)
|
insertElement(0)
|
||||||
{};
|
{};
|
||||||
|
|
||||||
@ -200,6 +199,9 @@ class nsTextRulesInfo : public nsRulesInfo
|
|||||||
// kAlign
|
// kAlign
|
||||||
const nsString *alignType;
|
const nsString *alignType;
|
||||||
|
|
||||||
|
// kMakeBasicBlock
|
||||||
|
const nsString *blockType;
|
||||||
|
|
||||||
// kInsertElement
|
// kInsertElement
|
||||||
const nsIDOMElement* insertElement;
|
const nsIDOMElement* insertElement;
|
||||||
};
|
};
|
||||||
|
@ -3153,7 +3153,8 @@ nsEditor::GetTag(nsIDOMNode *aNode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
|
||||||
content->GetTag(*getter_AddRefs(atom));
|
if (content)
|
||||||
|
content->GetTag(*getter_AddRefs(atom));
|
||||||
|
|
||||||
return atom;
|
return atom;
|
||||||
}
|
}
|
||||||
@ -3407,7 +3408,7 @@ nsEditor::NextNodeInBlock(nsIDOMNode *aNode, IterDirection aDir)
|
|||||||
if (NS_FAILED(iter->CurrentNode(getter_AddRefs(content)))) return nullNode;
|
if (NS_FAILED(iter->CurrentNode(getter_AddRefs(content)))) return nullNode;
|
||||||
// ignore nodes that aren't elements or text, or that are the block parent
|
// ignore nodes that aren't elements or text, or that are the block parent
|
||||||
node = do_QueryInterface(content);
|
node = do_QueryInterface(content);
|
||||||
if (node && IsTextOrElementNode(node) && (node != blockParent) && (node!=nsCOMPtr<nsIDOMNode>(dont_QueryInterface(aNode))))
|
if (node && IsTextOrElementNode(node) && (node != blockParent) && (node.get() != aNode))
|
||||||
return node;
|
return node;
|
||||||
|
|
||||||
if (aDir == kIterForward)
|
if (aDir == kIterForward)
|
||||||
@ -3680,7 +3681,7 @@ nsEditor::SplitNodeDeep(nsIDOMNode *aNode,
|
|||||||
if (!nodeAsText || (offset && (offset != textLen)))
|
if (!nodeAsText || (offset && (offset != textLen)))
|
||||||
{
|
{
|
||||||
bDoSplit = PR_TRUE;
|
bDoSplit = PR_TRUE;
|
||||||
nsresult res = SplitNode(nodeToSplit, offset, getter_AddRefs(tempNode));
|
res = SplitNode(nodeToSplit, offset, getter_AddRefs(tempNode));
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,12 +107,8 @@ nsHTMLEditRules::WillDoAction(nsIDOMSelection *aSelection,
|
|||||||
return WillOutdent(aSelection, aCancel);
|
return WillOutdent(aSelection, aCancel);
|
||||||
case kAlign:
|
case kAlign:
|
||||||
return WillAlign(aSelection, info->alignType, aCancel);
|
return WillAlign(aSelection, info->alignType, aCancel);
|
||||||
case kMakeHeader:
|
case kMakeBasicBlock:
|
||||||
return WillMakeHeader(aSelection, aCancel);
|
return WillMakeBasicBlock(aSelection, info->blockType, aCancel);
|
||||||
case kMakeAddress:
|
|
||||||
return WillMakeAddress(aSelection, aCancel);
|
|
||||||
case kMakePRE:
|
|
||||||
return WillMakePRE(aSelection, aCancel);
|
|
||||||
case kInsertElement:
|
case kInsertElement:
|
||||||
return WillInsert(aSelection, aCancel);
|
return WillInsert(aSelection, aCancel);
|
||||||
}
|
}
|
||||||
@ -258,7 +254,13 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel)
|
|||||||
return mEditor->InsertText(theString);
|
return mEditor->InsertText(theString);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMNode> blockParent = mEditor->GetBlockNodeParent(node);
|
nsCOMPtr<nsIDOMNode> blockParent;
|
||||||
|
|
||||||
|
if (nsEditor::IsBlockNode(node))
|
||||||
|
blockParent = node;
|
||||||
|
else
|
||||||
|
blockParent = mEditor->GetBlockNodeParent(node);
|
||||||
|
|
||||||
if (!blockParent) return NS_ERROR_FAILURE;
|
if (!blockParent) return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
// headers: put selection after the header
|
// headers: put selection after the header
|
||||||
@ -521,45 +523,18 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
|
|||||||
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
||||||
// initialize out param
|
// initialize out param
|
||||||
*aCancel = PR_FALSE;
|
*aCancel = PR_FALSE;
|
||||||
|
nsAutoString blockType("ul");
|
||||||
|
if (aOrdered) blockType = "ol";
|
||||||
|
|
||||||
nsAutoSelectionReset selectionResetter(aSelection);
|
nsAutoSelectionReset selectionResetter(aSelection);
|
||||||
nsresult res;
|
nsresult res;
|
||||||
|
|
||||||
// check for collapsed selection in empty block or after a <br>.
|
PRBool outMakeEmpty;
|
||||||
// Either way, we want to get the default behavior of creating
|
res = ShouldMakeEmptyBlock(aSelection, &blockType, &outMakeEmpty);
|
||||||
// an empty list.
|
|
||||||
|
|
||||||
PRBool isCollapsed;
|
|
||||||
res = aSelection->GetIsCollapsed(&isCollapsed);
|
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
if (isCollapsed)
|
if (outMakeEmpty) return NS_OK;
|
||||||
{
|
|
||||||
// is it after a <br>? Two possibilities: selection right after <br>;
|
|
||||||
// and selection at front of text node following <br>
|
|
||||||
nsCOMPtr<nsIDOMNode> parent, prevChild;
|
|
||||||
PRInt32 offset;
|
|
||||||
res = nsEditor::GetStartNodeAndOffset(aSelection, &parent, &offset);
|
|
||||||
if (nsEditor::IsTextNode(parent) && !offset)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIDOMNode> node = parent;
|
|
||||||
res = nsEditor::GetNodeLocation(node, &parent, &offset);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
}
|
|
||||||
if (offset)
|
|
||||||
{
|
|
||||||
prevChild = nsEditor::GetChildAt(parent, offset-1);
|
|
||||||
if (prevChild && IsBreak(prevChild))
|
|
||||||
return NS_OK; // insertion point after break
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise check for being in an empty block
|
|
||||||
PRBool isEmptyBlock;
|
|
||||||
res = IsEmptyBlock(parent, &isEmptyBlock);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
if (isEmptyBlock) return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ok, we aren't vreating a new empty list. Instead we are converting
|
// ok, we aren't creating a new empty list. Instead we are converting
|
||||||
// the set of blocks implied by the selection into a list.
|
// the set of blocks implied by the selection into a list.
|
||||||
|
|
||||||
// convert the selection ranges into "promoted" selection ranges:
|
// convert the selection ranges into "promoted" selection ranges:
|
||||||
@ -578,13 +553,6 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
|
|||||||
res = GetNodesForOperation(arrayOfRanges, &arrayOfNodes, kMakeList);
|
res = GetNodesForOperation(arrayOfRanges, &arrayOfNodes, kMakeList);
|
||||||
if (NS_FAILED(res)) return res;
|
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 from thinking about an array of
|
|
||||||
// nodes to act on to instead think of an array of ranges to act on.
|
|
||||||
|
|
||||||
// Remove all non-editable nodes. Leave them be.
|
// Remove all non-editable nodes. Leave them be.
|
||||||
|
|
||||||
PRUint32 listCount;
|
PRUint32 listCount;
|
||||||
@ -621,7 +589,7 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
|
|||||||
nsCOMPtr <nsIDOMNode> tmpNode = nsEditor::GetChildAt(curNode, 0);
|
nsCOMPtr <nsIDOMNode> tmpNode = nsEditor::GetChildAt(curNode, 0);
|
||||||
if (IsDiv(tmpNode) || IsOrderedList(tmpNode) || IsUnorderedList(tmpNode) || IsBlockquote(tmpNode))
|
if (IsDiv(tmpNode) || IsOrderedList(tmpNode) || IsUnorderedList(tmpNode) || IsBlockquote(tmpNode))
|
||||||
{
|
{
|
||||||
// check editablility XXX moose
|
// check editablility XXX floppy moose
|
||||||
curNode = tmpNode;
|
curNode = tmpNode;
|
||||||
}
|
}
|
||||||
else break;
|
else break;
|
||||||
@ -673,7 +641,6 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
|
|||||||
{
|
{
|
||||||
// make a new ordered list, insert it where the current unordered list is,
|
// make a new ordered list, insert it where the current unordered list is,
|
||||||
// and move all the children to the new list, and remove the old list
|
// and move all the children to the new list, and remove the old list
|
||||||
nsAutoString blockType("ol");
|
|
||||||
res = ReplaceContainer(curNode,&newBlock,blockType);
|
res = ReplaceContainer(curNode,&newBlock,blockType);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
curList = newBlock;
|
curList = newBlock;
|
||||||
@ -692,7 +659,6 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
|
|||||||
{
|
{
|
||||||
// make a new unordered list, insert it where the current ordered list is,
|
// make a new unordered list, insert it where the current ordered list is,
|
||||||
// and move all the children to the new list, and remove the old list
|
// and move all the children to the new list, and remove the old list
|
||||||
nsAutoString blockType("ul");
|
|
||||||
ReplaceContainer(curNode,&newBlock,blockType);
|
ReplaceContainer(curNode,&newBlock,blockType);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
curList = newBlock;
|
curList = newBlock;
|
||||||
@ -707,7 +673,7 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
|
|||||||
}
|
}
|
||||||
else if (IsDiv(curNode) || IsBlockquote(curNode))
|
else if (IsDiv(curNode) || IsBlockquote(curNode))
|
||||||
{
|
{
|
||||||
// XXX moose
|
// XXX floppy moose
|
||||||
}
|
}
|
||||||
} // lonely node
|
} // lonely node
|
||||||
|
|
||||||
@ -724,7 +690,7 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
|
|||||||
prevListItem = 0;
|
prevListItem = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if curNode is a Break, delete it, and quit remember prev list item
|
// if curNode is a Break, delete it, and quit remembering prev list item
|
||||||
if (IsBreak(curNode))
|
if (IsBreak(curNode))
|
||||||
{
|
{
|
||||||
res = mEditor->DeleteNode(curNode);
|
res = mEditor->DeleteNode(curNode);
|
||||||
@ -781,53 +747,35 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo
|
|||||||
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsHTMLEditRules::WillMakeHeader(nsIDOMSelection *aSelection, PRBool *aCancel)
|
nsHTMLEditRules::WillMakeBasicBlock(nsIDOMSelection *aSelection, const nsString *aBlockType, PRBool *aCancel)
|
||||||
{
|
{
|
||||||
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
||||||
// initialize out param
|
// initialize out param
|
||||||
*aCancel = PR_TRUE;
|
*aCancel = PR_FALSE;
|
||||||
|
|
||||||
|
PRBool makeEmpty;
|
||||||
|
nsresult res = ShouldMakeEmptyBlock(aSelection, aBlockType, &makeEmpty);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
if (makeEmpty) return res; // just insert a new empty block
|
||||||
|
|
||||||
|
// else it's not that easy...
|
||||||
nsAutoSelectionReset selectionResetter(aSelection);
|
nsAutoSelectionReset selectionResetter(aSelection);
|
||||||
nsresult res;
|
*aCancel = PR_TRUE;
|
||||||
|
|
||||||
// Get the ranges for each break-delimited block
|
|
||||||
nsCOMPtr<nsIEnumerator> enumerator;
|
|
||||||
res = aSelection->GetEnumerator(getter_AddRefs(enumerator));
|
|
||||||
if (NS_SUCCEEDED(res) && enumerator)
|
|
||||||
{
|
|
||||||
for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next())
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsISupports> currentItem;
|
|
||||||
res = enumerator->CurrentItem(getter_AddRefs(currentItem));
|
|
||||||
if ((NS_SUCCEEDED(res)) && (currentItem))
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
|
|
||||||
PRBool isCollapsed;
|
|
||||||
range->GetIsCollapsed(&isCollapsed);
|
|
||||||
if (PR_FALSE==isCollapsed) // don't make headers out of empty ranges
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsISupportsArray> arrayOfRanges;
|
|
||||||
res = mEditor->GetBlockSectionsForRange(range, arrayOfRanges);
|
|
||||||
PRUint32 rangeCount;
|
|
||||||
res = arrayOfRanges->Count(&rangeCount);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
|
|
||||||
PRInt32 i;
|
|
||||||
nsCOMPtr<nsIDOMRange> opRange;
|
|
||||||
nsCOMPtr<nsISupports> isupports;
|
|
||||||
|
|
||||||
for (i = 0; i < rangeCount; i++)
|
nsCOMPtr<nsISupportsArray> arrayOfRanges;
|
||||||
{
|
res = GetPromotedRanges(aSelection, &arrayOfRanges, kMakeBasicBlock);
|
||||||
isupports = (dont_AddRef)(arrayOfRanges->ElementAt(i));
|
if (NS_FAILED(res)) return res;
|
||||||
opRange = do_QueryInterface(isupports);
|
|
||||||
// ConvertRangeToTag
|
// use these ranges to contruct a list of nodes to act on.
|
||||||
}
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
||||||
}
|
res = GetNodesForOperation(arrayOfRanges, &arrayOfNodes, kMakeBasicBlock);
|
||||||
}
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
|
||||||
}
|
// Ok, now go through all the nodes and make the right kind of blocks,
|
||||||
// unfinished, just return NS_OK for now
|
// or whatever is approriate. Wohoo!
|
||||||
return NS_OK;
|
res = ApplyBlockStyle(arrayOfNodes, aBlockType);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1015,15 +963,22 @@ nsHTMLEditRules::WillAlign(nsIDOMSelection *aSelection, const nsString *alignTyp
|
|||||||
{
|
{
|
||||||
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
||||||
// initialize out param
|
// initialize out param
|
||||||
*aCancel = PR_TRUE;
|
*aCancel = PR_FALSE;
|
||||||
|
|
||||||
nsAutoSelectionReset selectionResetter(aSelection);
|
nsAutoSelectionReset selectionResetter(aSelection);
|
||||||
nsresult res = NS_OK;
|
nsresult res = NS_OK;
|
||||||
|
|
||||||
|
PRBool outMakeEmpty;
|
||||||
|
res = ShouldMakeEmptyBlock(aSelection, alignType, &outMakeEmpty);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
if (outMakeEmpty) return NS_OK;
|
||||||
|
|
||||||
|
|
||||||
// convert the selection ranges into "promoted" selection ranges:
|
// convert the selection ranges into "promoted" selection ranges:
|
||||||
// this basically just expands the range to include the immediate
|
// this basically just expands the range to include the immediate
|
||||||
// block parent, and then further expands to include any ancestors
|
// block parent, and then further expands to include any ancestors
|
||||||
// whose children are all in the range
|
// whose children are all in the range
|
||||||
|
*aCancel = PR_TRUE;
|
||||||
|
|
||||||
nsCOMPtr<nsISupportsArray> arrayOfRanges;
|
nsCOMPtr<nsISupportsArray> arrayOfRanges;
|
||||||
res = GetPromotedRanges(aSelection, &arrayOfRanges, kAlign);
|
res = GetPromotedRanges(aSelection, &arrayOfRanges, kAlign);
|
||||||
@ -1100,32 +1055,6 @@ nsHTMLEditRules::WillAlign(nsIDOMSelection *aSelection, const nsString *alignTyp
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
nsHTMLEditRules::WillMakeAddress(nsIDOMSelection *aSelection, PRBool *aCancel)
|
|
||||||
{
|
|
||||||
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
|
||||||
// initialize out param
|
|
||||||
*aCancel = PR_FALSE;
|
|
||||||
|
|
||||||
nsresult res = NS_OK;
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
nsHTMLEditRules::WillMakePRE(nsIDOMSelection *aSelection, PRBool *aCancel)
|
|
||||||
{
|
|
||||||
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
|
||||||
// initialize out param
|
|
||||||
*aCancel = PR_FALSE;
|
|
||||||
|
|
||||||
nsresult res = NS_OK;
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/********************************************************
|
/********************************************************
|
||||||
* helper methods
|
* helper methods
|
||||||
********************************************************/
|
********************************************************/
|
||||||
@ -1186,6 +1115,24 @@ nsHTMLEditRules::IsListItem(nsIDOMNode *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// IsList: true if node an html list
|
||||||
|
//
|
||||||
|
PRBool
|
||||||
|
nsHTMLEditRules::IsList(nsIDOMNode *node)
|
||||||
|
{
|
||||||
|
NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsList");
|
||||||
|
nsAutoString tag;
|
||||||
|
nsEditor::GetTagString(node,tag);
|
||||||
|
if ( (tag == "ol") ||
|
||||||
|
(tag == "ul") )
|
||||||
|
{
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// IsOrderedList: true if node an html orderd list
|
// IsOrderedList: true if node an html orderd list
|
||||||
//
|
//
|
||||||
@ -1345,6 +1292,9 @@ nsHTMLEditRules::IsEmptyBlock(nsIDOMNode *aNode, PRBool *outIsEmptyBlock)
|
|||||||
}
|
}
|
||||||
else // an editable, non-text node. we aren't an empty block
|
else // an editable, non-text node. we aren't an empty block
|
||||||
{
|
{
|
||||||
|
// is it the node we are iterating over?
|
||||||
|
if (node.get() == aNode) break;
|
||||||
|
// otherwise it ain't empty
|
||||||
*outIsEmptyBlock = PR_FALSE;
|
*outIsEmptyBlock = PR_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1451,12 +1401,21 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt
|
|||||||
nsCOMPtr<nsIDOMNode> parent = aNode;
|
nsCOMPtr<nsIDOMNode> parent = aNode;
|
||||||
PRInt32 offset = aOffset;
|
PRInt32 offset = aOffset;
|
||||||
|
|
||||||
|
if (IsBody(aNode))
|
||||||
|
{
|
||||||
|
// we cant go any higher
|
||||||
|
*outNode = do_QueryInterface(aNode);
|
||||||
|
*outOffset = aOffset;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
if (aWhere == kStart)
|
if (aWhere == kStart)
|
||||||
{
|
{
|
||||||
// some special casing for text nodes
|
// some special casing for text nodes
|
||||||
if (nsEditor::IsTextNode(aNode))
|
if (nsEditor::IsTextNode(aNode))
|
||||||
{
|
{
|
||||||
nsEditor::GetNodeLocation(aNode, &parent, &offset);
|
res = nsEditor::GetNodeLocation(aNode, &parent, &offset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1464,26 +1423,38 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt
|
|||||||
if (!node) node = parent;
|
if (!node) node = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this is an inline node, back up through any prior inline nodes that
|
// if this is an inline node who's block parent is the body,
|
||||||
// aren't across a <br> from us, and that are enclosed in the same block.
|
// back up through any prior inline nodes that
|
||||||
|
// aren't across a <br> from us.
|
||||||
|
|
||||||
if (!nsEditor::IsBlockNode(node))
|
if (!nsEditor::IsBlockNode(node))
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIDOMNode> prevNode;
|
nsCOMPtr<nsIDOMNode> block = nsEditor::GetBlockNodeParent(node);
|
||||||
prevNode = nsEditor::NextNodeInBlock(node, nsEditor::kIterBackward);
|
if (IsBody(block))
|
||||||
while (prevNode)
|
|
||||||
{
|
{
|
||||||
if (IsBreak(prevNode))
|
nsCOMPtr<nsIDOMNode> prevNode;
|
||||||
break;
|
|
||||||
if (nsEditor::IsBlockNode(prevNode))
|
|
||||||
break;
|
|
||||||
node = prevNode;
|
|
||||||
prevNode = nsEditor::NextNodeInBlock(node, nsEditor::kIterBackward);
|
prevNode = nsEditor::NextNodeInBlock(node, nsEditor::kIterBackward);
|
||||||
|
while (prevNode)
|
||||||
|
{
|
||||||
|
if (IsBreak(prevNode))
|
||||||
|
break;
|
||||||
|
if (nsEditor::IsBlockNode(prevNode))
|
||||||
|
break;
|
||||||
|
node = prevNode;
|
||||||
|
prevNode = nsEditor::NextNodeInBlock(node, nsEditor::kIterBackward);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// just grap the whole block
|
||||||
|
node = block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// finding the real start for this point. look up the tree for as long as we are the
|
// finding the real start for this point. look up the tree for as long as we are the
|
||||||
// first node in the container, and as long as we haven't hit the body node.
|
// first node in the container, and as long as we haven't hit the body node.
|
||||||
|
nsEditor::GetNodeLocation(node, &parent, &offset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
while ((IsFirstNode(node)) && (!IsBody(parent)))
|
while ((IsFirstNode(node)) && (!IsBody(parent)))
|
||||||
{
|
{
|
||||||
node = parent;
|
node = parent;
|
||||||
@ -1508,39 +1479,49 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt
|
|||||||
if (!node) node = parent;
|
if (!node) node = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node)
|
if (!node)
|
||||||
offset++; // since this is going to be used for a range _endpoint_, we want to be after the node
|
|
||||||
else
|
|
||||||
node = parent;
|
node = parent;
|
||||||
|
|
||||||
// if this is an inline node, look ahead through any further inline nodes that
|
// if this is an inline node who's block parent is the body,
|
||||||
|
// look ahead through any further inline nodes that
|
||||||
// aren't across a <br> from us, and that are enclosed in the same block.
|
// aren't across a <br> from us, and that are enclosed in the same block.
|
||||||
|
|
||||||
if (!nsEditor::IsBlockNode(node))
|
if (!nsEditor::IsBlockNode(node))
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIDOMNode> nextNode;
|
nsCOMPtr<nsIDOMNode> block = nsEditor::GetBlockNodeParent(node);
|
||||||
nextNode = nsEditor::NextNodeInBlock(node, nsEditor::kIterForward);
|
if (IsBody(block))
|
||||||
while (nextNode)
|
|
||||||
{
|
{
|
||||||
if (IsBreak(nextNode))
|
nsCOMPtr<nsIDOMNode> nextNode;
|
||||||
break;
|
|
||||||
if (nsEditor::IsBlockNode(nextNode))
|
|
||||||
break;
|
|
||||||
node = nextNode;
|
|
||||||
nextNode = nsEditor::NextNodeInBlock(node, nsEditor::kIterForward);
|
nextNode = nsEditor::NextNodeInBlock(node, nsEditor::kIterForward);
|
||||||
|
while (nextNode)
|
||||||
|
{
|
||||||
|
if (IsBreak(nextNode))
|
||||||
|
break;
|
||||||
|
if (nsEditor::IsBlockNode(nextNode))
|
||||||
|
break;
|
||||||
|
node = nextNode;
|
||||||
|
nextNode = nsEditor::NextNodeInBlock(node, nsEditor::kIterForward);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// just grap the whole block
|
||||||
|
node = block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// finding the real end for this point. look up the tree for as long as we are the
|
// finding the real end for this point. look up the tree for as long as we are the
|
||||||
// last node in the container, and as long as we haven't hit the body node.
|
// last node in the container, and as long as we haven't hit the body node.
|
||||||
|
nsEditor::GetNodeLocation(node, &parent, &offset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
while ((IsLastNode(node)) && (!IsBody(parent)))
|
while ((IsLastNode(node)) && (!IsBody(parent)))
|
||||||
{
|
{
|
||||||
node = parent;
|
node = parent;
|
||||||
res = nsEditor::GetNodeLocation(node, &parent, &offset);
|
res = nsEditor::GetNodeLocation(node, &parent, &offset);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
offset++;
|
|
||||||
}
|
}
|
||||||
*outNode = parent;
|
*outNode = parent;
|
||||||
|
offset++; // add one since this in an endpoint - want to be AFTER node.
|
||||||
*outOffset = offset;
|
*outOffset = offset;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -1669,6 +1650,41 @@ nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// GetChildNodesForOperation:
|
||||||
|
//
|
||||||
|
nsresult
|
||||||
|
nsHTMLEditRules::GetChildNodesForOperation(nsIDOMNode *inNode,
|
||||||
|
nsCOMPtr<nsISupportsArray> *outArrayOfNodes)
|
||||||
|
{
|
||||||
|
if (!inNode || !outArrayOfNodes) return NS_ERROR_NULL_POINTER;
|
||||||
|
|
||||||
|
nsresult res = NS_NewISupportsArray(getter_AddRefs(*outArrayOfNodes));
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMNodeList> childNodes;
|
||||||
|
res = inNode->GetChildNodes(getter_AddRefs(childNodes));
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
PRUint32 childCount;
|
||||||
|
res = childNodes->GetLength(&childCount);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
PRUint32 i;
|
||||||
|
nsCOMPtr<nsIDOMNode> node;
|
||||||
|
nsCOMPtr<nsISupports> isupports;
|
||||||
|
for (i = 0; i < childCount; i++)
|
||||||
|
{
|
||||||
|
res = childNodes->Item( i, getter_AddRefs(node));
|
||||||
|
if (!node) return NS_ERROR_FAILURE;
|
||||||
|
isupports = do_QueryInterface(node);
|
||||||
|
(*outArrayOfNodes)->AppendElement(isupports);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// MakeTransitionList: detect all the transitions in the array, where a
|
// MakeTransitionList: detect all the transitions in the array, where a
|
||||||
// transition means that adjacent nodes in the array
|
// transition means that adjacent nodes in the array
|
||||||
@ -1716,7 +1732,7 @@ nsHTMLEditRules::MakeTransitionList(nsISupportsArray *inArrayOfNodes,
|
|||||||
nsresult
|
nsresult
|
||||||
nsHTMLEditRules::ReplaceContainer(nsIDOMNode *inNode,
|
nsHTMLEditRules::ReplaceContainer(nsIDOMNode *inNode,
|
||||||
nsCOMPtr<nsIDOMNode> *outNode,
|
nsCOMPtr<nsIDOMNode> *outNode,
|
||||||
nsString &aNodeType)
|
const nsString &aNodeType)
|
||||||
{
|
{
|
||||||
if (!inNode || !outNode)
|
if (!inNode || !outNode)
|
||||||
return NS_ERROR_NULL_POINTER;
|
return NS_ERROR_NULL_POINTER;
|
||||||
@ -1733,13 +1749,12 @@ nsHTMLEditRules::ReplaceContainer(nsIDOMNode *inNode,
|
|||||||
offset = 0;
|
offset = 0;
|
||||||
while (bHasMoreChildren)
|
while (bHasMoreChildren)
|
||||||
{
|
{
|
||||||
inNode->GetFirstChild(getter_AddRefs(child));
|
inNode->GetLastChild(getter_AddRefs(child));
|
||||||
res = mEditor->DeleteNode(child);
|
res = mEditor->DeleteNode(child);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
res = mEditor->InsertNode(child, *outNode, offset);
|
res = mEditor->InsertNode(child, *outNode, 0);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
inNode->HasChildNodes(&bHasMoreChildren);
|
inNode->HasChildNodes(&bHasMoreChildren);
|
||||||
offset++;
|
|
||||||
}
|
}
|
||||||
res = mEditor->DeleteNode(inNode);
|
res = mEditor->DeleteNode(inNode);
|
||||||
return res;
|
return res;
|
||||||
@ -1952,42 +1967,43 @@ nsHTMLEditRules::InsertSpace(nsIDOMSelection *aSelection,
|
|||||||
nsresult
|
nsresult
|
||||||
nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection,
|
nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection,
|
||||||
nsIDOMNode *aHeader,
|
nsIDOMNode *aHeader,
|
||||||
nsIDOMNode *aTextNode,
|
nsIDOMNode *aNode,
|
||||||
PRInt32 aOffset)
|
PRInt32 aOffset)
|
||||||
{
|
{
|
||||||
if (!aSelection || !aHeader || !aTextNode) return NS_ERROR_NULL_POINTER;
|
if (!aSelection || !aHeader || !aNode) return NS_ERROR_NULL_POINTER;
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMNode> leftNode;
|
// remeber where the header is
|
||||||
nsCOMPtr<nsIDOMNode> textNode = do_QueryInterface(aTextNode); // to hold a ref across the delete call
|
nsCOMPtr<nsIDOMNode> headerParent;
|
||||||
// split the node
|
PRInt32 offset;
|
||||||
nsresult res = mEditor->SplitNode(aTextNode, aOffset, getter_AddRefs(leftNode));
|
nsresult res = nsEditor::GetNodeLocation(aHeader, &headerParent, &offset);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
// move the right node outside of the header, via deletion/insertion
|
|
||||||
// delete the right node
|
|
||||||
res = mEditor->DeleteNode(textNode);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
|
|
||||||
// insert the right node
|
|
||||||
nsCOMPtr<nsIDOMNode> p;
|
|
||||||
aHeader->GetParentNode(getter_AddRefs(p));
|
|
||||||
PRInt32 indx = mEditor->GetIndexOf(p,aHeader);
|
|
||||||
res = mEditor->InsertNode(textNode,p,indx+1);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
|
|
||||||
// merge text node with like sibling, if any
|
|
||||||
nsCOMPtr<nsIDOMNode> sibling;
|
|
||||||
textNode->GetNextSibling(getter_AddRefs(sibling));
|
|
||||||
if (sibling && mEditor->IsTextNode(sibling) && mEditor->IsEditable(sibling))
|
|
||||||
{
|
|
||||||
res = mEditor->JoinNodes(textNode,sibling,p);
|
|
||||||
if (NS_FAILED(res)) return res;
|
|
||||||
textNode = sibling; // sibling was the node kept by the join; remember it in "textNode"
|
|
||||||
}
|
|
||||||
|
|
||||||
// position selection before inserted node
|
|
||||||
res = aSelection->Collapse(textNode,0);
|
|
||||||
|
|
||||||
|
// split the header
|
||||||
|
PRInt32 newOffset;
|
||||||
|
res = mEditor->SplitNodeDeep( aHeader, aNode, aOffset, &newOffset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
// revisit the below when we move to using divs as standard paragraphs.
|
||||||
|
// need to create an "empty" div in the fisrt case below, and need to
|
||||||
|
// use a div instead of a <p> in the second case below
|
||||||
|
|
||||||
|
// if the new (righthand) header node is empty, delete it
|
||||||
|
PRBool isEmpty;
|
||||||
|
res = IsEmptyBlock(aHeader, &isEmpty);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
if (isEmpty)
|
||||||
|
{
|
||||||
|
res = mEditor->DeleteNode(aHeader);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = aSelection->Collapse(headerParent,offset+1);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
// else rewrap it in a paragraph
|
||||||
|
nsCOMPtr<nsIDOMNode> newBlock;
|
||||||
|
nsAutoString blockType("p");
|
||||||
|
res = ReplaceContainer(aHeader,&newBlock,blockType);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = aSelection->Collapse(newBlock,0);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2097,12 +2113,282 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,
|
|||||||
PRInt32 aOffset)
|
PRInt32 aOffset)
|
||||||
{
|
{
|
||||||
if (!aSelection || !aListItem || !aNode) return NS_ERROR_NULL_POINTER;
|
if (!aSelection || !aListItem || !aNode) return NS_ERROR_NULL_POINTER;
|
||||||
|
nsresult res = NS_OK;
|
||||||
PRInt32 newOffset;
|
|
||||||
nsresult res = mEditor->SplitNodeDeep( aListItem, aNode, aOffset, &newOffset);
|
nsCOMPtr<nsIDOMNode> listitem;
|
||||||
|
|
||||||
|
// sanity check
|
||||||
|
NS_PRECONDITION(PR_TRUE == IsListItem(aListItem), "expected a list item and didnt get one");
|
||||||
|
|
||||||
|
// if we are in an empty listitem, then we want to pop up out of the list
|
||||||
|
PRBool isEmpty;
|
||||||
|
res = IsEmptyBlock(aListItem, &isEmpty);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
res = aSelection->Collapse(aNode,0);
|
if (isEmpty)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIDOMNode> list, listparent;
|
||||||
|
PRInt32 offset;
|
||||||
|
list = nsEditor::GetBlockNodeParent(aListItem);
|
||||||
|
res = nsEditor::GetNodeLocation(list, &listparent, &offset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
// are we in a sublist?
|
||||||
|
if (IsList(listparent)) //in a sublist
|
||||||
|
{
|
||||||
|
// if so, move this list item out of this list and into the grandparent list
|
||||||
|
res = mEditor->DeleteNode(aListItem);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = mEditor->InsertNode(aListItem,listparent,offset+1);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = aSelection->Collapse(aListItem,0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// otherwise kill this listitem and set the selection to after the parent list
|
||||||
|
res = mEditor->DeleteNode(aListItem);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = aSelection->Collapse(listparent,offset+1);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// else we want a new list item at the same list level
|
||||||
|
PRInt32 newOffset;
|
||||||
|
res = mEditor->SplitNodeDeep( aListItem, aNode, aOffset, &newOffset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = aSelection->Collapse(aListItem,0);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// ShouldMakeEmptyBlock: determine if a block transformation should make
|
||||||
|
// a new empty block, or instead transform a block
|
||||||
|
//
|
||||||
|
nsresult
|
||||||
|
nsHTMLEditRules::ShouldMakeEmptyBlock(nsIDOMSelection *aSelection,
|
||||||
|
const nsString *blockTag,
|
||||||
|
PRBool *outMakeEmpty)
|
||||||
|
{
|
||||||
|
// a note about strategy:
|
||||||
|
// this routine will be called by the rules code to figure out
|
||||||
|
// if it should do something, or let the nsHTMLEditor default
|
||||||
|
// action happen. The default action is to insert a new block.
|
||||||
|
// Note that if _nothing_ should happen, ie, the selection is
|
||||||
|
// already entireyl inside a block (or blocks) or the correct type,
|
||||||
|
// then you don't want to return true in outMakeEmpty, since the
|
||||||
|
// defualt code will insert a new empty block anyway, rather than
|
||||||
|
// doing nothing. So we have to detect that case and return false.
|
||||||
|
|
||||||
|
if (!aSelection || !outMakeEmpty) return NS_ERROR_NULL_POINTER;
|
||||||
|
nsresult res = NS_OK;
|
||||||
|
|
||||||
|
// if the selection is collapsed, and
|
||||||
|
// if we in the body, or after a <br> with
|
||||||
|
// no more inline content before the next block, then we want
|
||||||
|
// a new block. Otherwise we want to trasform a block
|
||||||
|
|
||||||
|
// xxx possible bug: selection could be not callapsed, but
|
||||||
|
// still empty. it would be nice to have a call for this: IsEmptySelection()
|
||||||
|
|
||||||
|
PRBool isCollapsed;
|
||||||
|
res = aSelection->GetIsCollapsed(&isCollapsed);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
if (isCollapsed)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIDOMNode> parent;
|
||||||
|
PRInt32 offset;
|
||||||
|
res = nsEditor::GetStartNodeAndOffset(aSelection, &parent, &offset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
// is selection point in the body?
|
||||||
|
if (IsBody(parent))
|
||||||
|
{
|
||||||
|
*outMakeEmpty = PR_TRUE;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if block parent is already right kind of block.
|
||||||
|
// See strategy comment above.
|
||||||
|
nsCOMPtr<nsIDOMNode> block;
|
||||||
|
if (!nsEditor::IsBlockNode(parent))
|
||||||
|
block = nsEditor::GetBlockNodeParent(parent);
|
||||||
|
else
|
||||||
|
block = parent;
|
||||||
|
if (block)
|
||||||
|
{
|
||||||
|
nsAutoString tag;
|
||||||
|
nsEditor::GetTagString(block,tag);
|
||||||
|
if (tag == *blockTag)
|
||||||
|
{
|
||||||
|
*outMakeEmpty = PR_FALSE;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// are we in a textnode or inline node?
|
||||||
|
if (!nsEditor::IsBlockNode(parent))
|
||||||
|
{
|
||||||
|
// we must be in a text or inline node - convert existing block
|
||||||
|
*outMakeEmpty = PR_FALSE;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// is it after a <br> with no inline nodes after it, or a <br> after it??
|
||||||
|
if (offset)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIDOMNode> prevChild, nextChild, tmp;
|
||||||
|
prevChild = nsEditor::GetChildAt(parent, offset-1);
|
||||||
|
while (prevChild && !mEditor->IsEditable(prevChild))
|
||||||
|
{
|
||||||
|
// search back until we either find an editable node,
|
||||||
|
// or hit the beginning of the block
|
||||||
|
tmp = nsEditor::NextNodeInBlock(prevChild, nsEditor::kIterBackward);
|
||||||
|
prevChild = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevChild && IsBreak(prevChild))
|
||||||
|
{
|
||||||
|
nextChild = nsEditor::GetChildAt(parent, offset);
|
||||||
|
while (nextChild && !mEditor->IsEditable(nextChild))
|
||||||
|
{
|
||||||
|
// search back until we either find an editable node,
|
||||||
|
// or hit the beginning of the block
|
||||||
|
tmp = nsEditor::NextNodeInBlock(nextChild, nsEditor::kIterForward);
|
||||||
|
nextChild = tmp;
|
||||||
|
}
|
||||||
|
if (!nextChild || IsBreak(nextChild) || nsEditor::IsBlockNode(nextChild))
|
||||||
|
{
|
||||||
|
// we are after a <br> and not before inline content,
|
||||||
|
// or we are between <br>s.
|
||||||
|
// make an empty block
|
||||||
|
*outMakeEmpty = PR_FALSE;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// otherwise transform an existing block
|
||||||
|
*outMakeEmpty = PR_FALSE;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// ApplyBlockStyle: do whatever it takes to make the list of nodes into
|
||||||
|
// one or more blocks of type blockTag.
|
||||||
|
//
|
||||||
|
nsresult
|
||||||
|
nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString *aBlockTag)
|
||||||
|
{
|
||||||
|
// intent of this routine is to be used for converting to/from
|
||||||
|
// headers, paragraphs (or moz-divs), pre, and address. Those blocks
|
||||||
|
// that pretty much just contain inline things...
|
||||||
|
|
||||||
|
if (!arrayOfNodes || !aBlockTag) return NS_ERROR_NULL_POINTER;
|
||||||
|
nsresult res = NS_OK;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMNode> curNode, curParent, curBlock, newBlock;
|
||||||
|
PRInt32 offset;
|
||||||
|
PRUint32 listCount;
|
||||||
|
arrayOfNodes->Count(&listCount);
|
||||||
|
|
||||||
|
PRUint32 i;
|
||||||
|
for (i=0; i<listCount; i++)
|
||||||
|
{
|
||||||
|
// get the node to act on, and it's location
|
||||||
|
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
||||||
|
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
|
||||||
|
res = nsEditor::GetNodeLocation(curNode, &curParent, &offset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
nsAutoString curNodeTag;
|
||||||
|
nsEditor::GetTagString(curNode, curNodeTag);
|
||||||
|
|
||||||
|
|
||||||
|
// is it already the right kind of block?
|
||||||
|
if (curNodeTag == *aBlockTag)
|
||||||
|
{
|
||||||
|
curBlock = 0; // forget any previous block used for previous inline nodes
|
||||||
|
continue; // do nothing to this block
|
||||||
|
}
|
||||||
|
|
||||||
|
// if curNode is a <pre> and we are converting to non-pre, we need
|
||||||
|
// to process the text inside the <pre> so as to convert returns
|
||||||
|
// to breaks, and runs of spaces to nbsps.
|
||||||
|
// xxx floppy moose
|
||||||
|
|
||||||
|
// if curNode is a p, header, address, or pre, replace
|
||||||
|
// it with a new block of correct type.
|
||||||
|
// xxx floppy moose: pre cant hold everything the others can
|
||||||
|
if ((curNodeTag == "pre") ||
|
||||||
|
(curNodeTag == "p") ||
|
||||||
|
(curNodeTag == "h1") ||
|
||||||
|
(curNodeTag == "h2") ||
|
||||||
|
(curNodeTag == "h3") ||
|
||||||
|
(curNodeTag == "h4") ||
|
||||||
|
(curNodeTag == "h5") ||
|
||||||
|
(curNodeTag == "h6") ||
|
||||||
|
(curNodeTag == "address"))
|
||||||
|
{
|
||||||
|
curBlock = 0; // forget any previous block used for previous inline nodes
|
||||||
|
res = ReplaceContainer(curNode, &newBlock, *aBlockTag);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
}
|
||||||
|
else if ((curNodeTag == "table") ||
|
||||||
|
(curNodeTag == "tbody") ||
|
||||||
|
(curNodeTag == "tr") ||
|
||||||
|
(curNodeTag == "td") ||
|
||||||
|
(curNodeTag == "ol") ||
|
||||||
|
(curNodeTag == "ul") ||
|
||||||
|
(curNodeTag == "li") ||
|
||||||
|
(curNodeTag == "blockquote") ||
|
||||||
|
(curNodeTag == "div"))
|
||||||
|
{
|
||||||
|
curBlock = 0; // forget any previous block used for previous inline nodes
|
||||||
|
// recursion time
|
||||||
|
nsCOMPtr<nsISupportsArray> childArray;
|
||||||
|
res = GetChildNodesForOperation(curNode, &childArray);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = ApplyBlockStyle(childArray, aBlockTag);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if curNode is inline, pull it into curBlock
|
||||||
|
// note: it's assumed that consecutive inline nodes in the
|
||||||
|
// arrayOfNodes are actually members of the same block parent.
|
||||||
|
// this happens to be true now as a side effect of how
|
||||||
|
// arrayOfNodes is contructed, but some additional logic should
|
||||||
|
// be added here if that should change
|
||||||
|
|
||||||
|
else if (nsEditor::IsInlineNode(curNode))
|
||||||
|
{
|
||||||
|
// if curNode is a non editable, drop it if we are going to <pre>
|
||||||
|
if ((*aBlockTag == "pre") && (!mEditor->IsEditable(curNode)))
|
||||||
|
continue; // do nothing to this block
|
||||||
|
|
||||||
|
// if no curBlock, make one
|
||||||
|
if (!curBlock)
|
||||||
|
{
|
||||||
|
res = mEditor->CreateNode(*aBlockTag, curParent, offset, getter_AddRefs(curBlock));
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if curNode is a Break, replace it with a return if we are going to <pre>
|
||||||
|
// xxx floppy moose
|
||||||
|
|
||||||
|
// this is a continuation of some inline nodes that belong together in
|
||||||
|
// the same block item. use curBlock
|
||||||
|
PRUint32 blockLen;
|
||||||
|
res = mEditor->GetLengthOfDOMNode(curBlock, blockLen);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = mEditor->DeleteNode(curNode);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = mEditor->InsertNode(curNode, curBlock, blockLen);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,12 +39,6 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
enum IterDirection
|
|
||||||
{
|
|
||||||
kIterForward,
|
|
||||||
kIterBackward
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RulesEndpoint
|
enum RulesEndpoint
|
||||||
{
|
{
|
||||||
kStart,
|
kStart,
|
||||||
@ -66,9 +60,7 @@ protected:
|
|||||||
nsresult WillIndent(nsIDOMSelection *aSelection, PRBool *aCancel);
|
nsresult WillIndent(nsIDOMSelection *aSelection, PRBool *aCancel);
|
||||||
nsresult WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel);
|
nsresult WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel);
|
||||||
nsresult WillAlign(nsIDOMSelection *aSelection, const nsString *alignType, PRBool *aCancel);
|
nsresult WillAlign(nsIDOMSelection *aSelection, const nsString *alignType, PRBool *aCancel);
|
||||||
nsresult WillMakeHeader(nsIDOMSelection *aSelection, PRBool *aCancel);
|
nsresult WillMakeBasicBlock(nsIDOMSelection *aSelection, const nsString *aBlockType, PRBool *aCancel);
|
||||||
nsresult WillMakeAddress(nsIDOMSelection *aSelection, PRBool *aCancel);
|
|
||||||
nsresult WillMakePRE(nsIDOMSelection *aSelection, PRBool *aCancel);
|
|
||||||
|
|
||||||
nsresult InsertTab(nsIDOMSelection *aSelection, PRBool *aCancel, PlaceholderTxn **aTxn, nsString *outString);
|
nsresult InsertTab(nsIDOMSelection *aSelection, PRBool *aCancel, PlaceholderTxn **aTxn, nsString *outString);
|
||||||
nsresult InsertSpace(nsIDOMSelection *aSelection, PRBool *aCancel, PlaceholderTxn **aTxn, nsString *outString);
|
nsresult InsertSpace(nsIDOMSelection *aSelection, PRBool *aCancel, PlaceholderTxn **aTxn, nsString *outString);
|
||||||
@ -84,6 +76,7 @@ protected:
|
|||||||
static PRBool IsHeader(nsIDOMNode *aNode);
|
static PRBool IsHeader(nsIDOMNode *aNode);
|
||||||
static PRBool IsParagraph(nsIDOMNode *aNode);
|
static PRBool IsParagraph(nsIDOMNode *aNode);
|
||||||
static PRBool IsListItem(nsIDOMNode *aNode);
|
static PRBool IsListItem(nsIDOMNode *aNode);
|
||||||
|
static PRBool IsList(nsIDOMNode *aNode);
|
||||||
static PRBool IsUnorderedList(nsIDOMNode *aNode);
|
static PRBool IsUnorderedList(nsIDOMNode *aNode);
|
||||||
static PRBool IsOrderedList(nsIDOMNode *aNode);
|
static PRBool IsOrderedList(nsIDOMNode *aNode);
|
||||||
static PRBool IsBreak(nsIDOMNode *aNode);
|
static PRBool IsBreak(nsIDOMNode *aNode);
|
||||||
@ -94,19 +87,24 @@ protected:
|
|||||||
nsresult IsEmptyBlock(nsIDOMNode *aNode, PRBool *outIsEmptyBlock);
|
nsresult IsEmptyBlock(nsIDOMNode *aNode, PRBool *outIsEmptyBlock);
|
||||||
PRBool IsFirstNode(nsIDOMNode *aNode);
|
PRBool IsFirstNode(nsIDOMNode *aNode);
|
||||||
PRBool IsLastNode(nsIDOMNode *aNode);
|
PRBool IsLastNode(nsIDOMNode *aNode);
|
||||||
|
|
||||||
nsresult GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt32 aOffset,
|
nsresult GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt32 aOffset,
|
||||||
PRInt32 actionID, nsCOMPtr<nsIDOMNode> *outNode, PRInt32 *outOffset);
|
PRInt32 actionID, nsCOMPtr<nsIDOMNode> *outNode, PRInt32 *outOffset);
|
||||||
|
|
||||||
nsresult GetPromotedRanges(nsIDOMSelection *inSelection,
|
nsresult GetPromotedRanges(nsIDOMSelection *inSelection,
|
||||||
nsCOMPtr<nsISupportsArray> *outArrayOfRanges,
|
nsCOMPtr<nsISupportsArray> *outArrayOfRanges,
|
||||||
PRInt32 inOperationType);
|
PRInt32 inOperationType);
|
||||||
static nsresult GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
|
nsresult GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
|
||||||
nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
||||||
PRInt32 inOperationType);
|
PRInt32 inOperationType);
|
||||||
static nsresult MakeTransitionList(nsISupportsArray *inArrayOfNodes,
|
nsresult GetChildNodesForOperation(nsIDOMNode *inNode,
|
||||||
|
nsCOMPtr<nsISupportsArray> *outArrayOfNodes);
|
||||||
|
nsresult MakeTransitionList(nsISupportsArray *inArrayOfNodes,
|
||||||
nsVoidArray *inTransitionArray);
|
nsVoidArray *inTransitionArray);
|
||||||
|
|
||||||
nsresult ReplaceContainer(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, nsString &aNodeType);
|
nsresult ShouldMakeEmptyBlock(nsIDOMSelection *aSelection, const nsString *blockTag, PRBool *outMakeEmpty);
|
||||||
|
nsresult ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString *aBlockTag);
|
||||||
|
|
||||||
|
nsresult ReplaceContainer(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, const nsString &aNodeType);
|
||||||
nsresult RemoveContainer(nsIDOMNode *inNode);
|
nsresult RemoveContainer(nsIDOMNode *inNode);
|
||||||
nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, nsString &aNodeType);
|
nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, nsString &aNodeType);
|
||||||
|
|
||||||
|
@ -1317,14 +1317,17 @@ NS_IMETHODIMP nsHTMLEditor::SetParagraphFormat(const nsString& aParagraphFormat)
|
|||||||
//Kinda sad to waste memory just to force lower case
|
//Kinda sad to waste memory just to force lower case
|
||||||
nsAutoString tag = aParagraphFormat;
|
nsAutoString tag = aParagraphFormat;
|
||||||
tag.ToLowerCase();
|
tag.ToLowerCase();
|
||||||
if (tag == "normal" || tag == "p") {
|
if (tag == "normal")
|
||||||
res = RemoveParagraphStyle();
|
{
|
||||||
} else if (tag == "li") {
|
res = InsertBasicBlock("p");
|
||||||
|
}
|
||||||
|
else if (tag == "li")
|
||||||
|
{
|
||||||
res = InsertList("ul");
|
res = InsertList("ul");
|
||||||
} else if (tag[0] == 'h') {
|
}
|
||||||
res = InsertHeader(tag);
|
else
|
||||||
} else {
|
{
|
||||||
res = ReplaceBlockParent(tag);
|
res = InsertBasicBlock(tag);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -1646,6 +1649,7 @@ nsHTMLEditor::InsertList(const nsString& aListType)
|
|||||||
// XXX - revisit when layout is fixed
|
// XXX - revisit when layout is fixed
|
||||||
res = selection->Collapse(newItem,0);
|
res = selection->Collapse(newItem,0);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
#if 0
|
||||||
nsAutoString theText(" ");
|
nsAutoString theText(" ");
|
||||||
res = InsertText(theText);
|
res = InsertText(theText);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
@ -1654,6 +1658,7 @@ nsHTMLEditor::InsertList(const nsString& aListType)
|
|||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
res = selection->Collapse(node,0);
|
res = selection->Collapse(node,0);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -1661,13 +1666,13 @@ nsHTMLEditor::InsertList(const nsString& aListType)
|
|||||||
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsHTMLEditor::InsertHeader(const nsString& aHeaderType)
|
nsHTMLEditor::InsertBasicBlock(const nsString& aBlockType)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_JS_EDITOR_LOG
|
#ifdef ENABLE_JS_EDITOR_LOG
|
||||||
nsAutoJSEditorLogLock logLock(mJSEditorLog);
|
nsAutoJSEditorLogLock logLock(mJSEditorLog);
|
||||||
|
|
||||||
if (mJSEditorLog)
|
if (mJSEditorLog)
|
||||||
mJSEditorLog->InsertHeader(aHeaderType);
|
mJSEditorLog->InsertBasicBlock(aBlockType);
|
||||||
#endif // ENABLE_JS_EDITOR_LOG
|
#endif // ENABLE_JS_EDITOR_LOG
|
||||||
|
|
||||||
nsresult res;
|
nsresult res;
|
||||||
@ -1680,7 +1685,8 @@ nsHTMLEditor::InsertHeader(const nsString& aHeaderType)
|
|||||||
|
|
||||||
// pre-process
|
// pre-process
|
||||||
nsEditor::GetSelection(getter_AddRefs(selection));
|
nsEditor::GetSelection(getter_AddRefs(selection));
|
||||||
nsTextRulesInfo ruleInfo(nsHTMLEditRules::kMakeHeader);
|
nsTextRulesInfo ruleInfo(nsHTMLEditRules::kMakeBasicBlock);
|
||||||
|
ruleInfo.blockType = &aBlockType;
|
||||||
res = mRules->WillDoAction(selection, &ruleInfo, &cancel);
|
res = mRules->WillDoAction(selection, &ruleInfo, &cancel);
|
||||||
if (cancel || (NS_FAILED(res))) return res;
|
if (cancel || (NS_FAILED(res))) return res;
|
||||||
|
|
||||||
@ -1700,12 +1706,12 @@ nsHTMLEditor::InsertHeader(const nsString& aHeaderType)
|
|||||||
|
|
||||||
if (isCollapsed)
|
if (isCollapsed)
|
||||||
{
|
{
|
||||||
// have to find a place to put the header
|
// have to find a place to put the block
|
||||||
nsCOMPtr<nsIDOMNode> parent = node;
|
nsCOMPtr<nsIDOMNode> parent = node;
|
||||||
nsCOMPtr<nsIDOMNode> topChild = node;
|
nsCOMPtr<nsIDOMNode> topChild = node;
|
||||||
nsCOMPtr<nsIDOMNode> tmp;
|
nsCOMPtr<nsIDOMNode> tmp;
|
||||||
|
|
||||||
while ( !CanContainTag(parent, aHeaderType))
|
while ( !CanContainTag(parent, aBlockType))
|
||||||
{
|
{
|
||||||
parent->GetParentNode(getter_AddRefs(tmp));
|
parent->GetParentNode(getter_AddRefs(tmp));
|
||||||
if (!tmp) return NS_ERROR_FAILURE;
|
if (!tmp) return NS_ERROR_FAILURE;
|
||||||
@ -1720,9 +1726,23 @@ nsHTMLEditor::InsertHeader(const nsString& aHeaderType)
|
|||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make a header
|
// make a block
|
||||||
nsCOMPtr<nsIDOMNode> newHeader;
|
nsCOMPtr<nsIDOMNode> newBlock;
|
||||||
res = CreateNode(aHeaderType, parent, offset, getter_AddRefs(newHeader));
|
res = CreateNode(aBlockType, parent, offset, getter_AddRefs(newBlock));
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
|
||||||
|
// xxx
|
||||||
|
|
||||||
|
// put a space in it so layout will draw it
|
||||||
|
res = selection->Collapse(newBlock,0);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
nsAutoString theText(nbsp);
|
||||||
|
res = InsertText(theText);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
// reposition selection to before the space character
|
||||||
|
res = GetStartNodeAndOffset(selection, &node, &offset);
|
||||||
|
if (NS_FAILED(res)) return res;
|
||||||
|
res = selection->Collapse(node,0);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ public:
|
|||||||
NS_IMETHOD RemoveParent(const nsString &aParentTag);
|
NS_IMETHOD RemoveParent(const nsString &aParentTag);
|
||||||
|
|
||||||
NS_IMETHOD InsertList(const nsString& aListType);
|
NS_IMETHOD InsertList(const nsString& aListType);
|
||||||
NS_IMETHOD InsertHeader(const nsString& aHeaderType);
|
NS_IMETHOD InsertBasicBlock(const nsString& aBlockType);
|
||||||
NS_IMETHOD Indent(const nsString& aIndent);
|
NS_IMETHOD Indent(const nsString& aIndent);
|
||||||
NS_IMETHOD Align(const nsString& aAlign);
|
NS_IMETHOD Align(const nsString& aAlign);
|
||||||
|
|
||||||
|
@ -73,9 +73,7 @@ public:
|
|||||||
kIndent = 3002,
|
kIndent = 3002,
|
||||||
kOutdent = 3003,
|
kOutdent = 3003,
|
||||||
kAlign = 3004,
|
kAlign = 3004,
|
||||||
kMakeHeader = 3005,
|
kMakeBasicBlock = 3005,
|
||||||
kMakeAddress = 3006,
|
|
||||||
kMakePRE = 3007,
|
|
||||||
kInsertElement = 3008
|
kInsertElement = 3008
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -179,6 +177,7 @@ class nsTextRulesInfo : public nsRulesInfo
|
|||||||
collapsedAction(nsIEditor::eDeleteNext),
|
collapsedAction(nsIEditor::eDeleteNext),
|
||||||
bOrdered(PR_FALSE),
|
bOrdered(PR_FALSE),
|
||||||
alignType(0),
|
alignType(0),
|
||||||
|
blockType(0),
|
||||||
insertElement(0)
|
insertElement(0)
|
||||||
{};
|
{};
|
||||||
|
|
||||||
@ -200,6 +199,9 @@ class nsTextRulesInfo : public nsRulesInfo
|
|||||||
// kAlign
|
// kAlign
|
||||||
const nsString *alignType;
|
const nsString *alignType;
|
||||||
|
|
||||||
|
// kMakeBasicBlock
|
||||||
|
const nsString *blockType;
|
||||||
|
|
||||||
// kInsertElement
|
// kInsertElement
|
||||||
const nsIDOMElement* insertElement;
|
const nsIDOMElement* insertElement;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user