implementing font increase/decrease size for html editor (bug 18774) r=floppy moose

This commit is contained in:
jfrancis%netscape.com 2000-02-08 12:53:34 +00:00
parent f51f453392
commit c9505c0fa5
24 changed files with 1058 additions and 394 deletions

View File

@ -49,7 +49,7 @@ class nsEditRules
public:
NS_IMETHOD Init(nsHTMLEditor *aEditor, PRUint32 aFlags)=0;
NS_IMETHOD BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection)=0;
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)=0;
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection, PRBool aSetSelection)=0;
NS_IMETHOD WillDoAction(nsIDOMSelection *aSelection, nsRulesInfo *aInfo, PRBool *aCancel, PRBool *aHandled)=0;
NS_IMETHOD DidDoAction(nsIDOMSelection *aSelection, nsRulesInfo *aInfo, nsresult aResult)=0;
NS_IMETHOD GetFlags(PRUint32 *aFlags)=0;

View File

@ -1787,7 +1787,7 @@ nsEditor::StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
/** All editor operations which alter the doc should be followed
* with a call to EndOperation, naming the action and direction */
NS_IMETHODIMP
nsEditor::EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
nsEditor::EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection, PRBool aSetSelection)
{
return NS_OK;
}
@ -3304,22 +3304,41 @@ nsEditor::NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag)
}
PRBool
nsEditor::CanContainTag(nsIDOMNode* aParent, const nsString &aTag)
nsEditor::CanContainTag(nsIDOMNode* aParent, const nsString &aChildTag)
{
// if we don't have a dtd then assume we can insert whatever want
if (!mDTD) return PR_TRUE;
PRInt32 childTagEnum, parentTagEnum;
nsAutoString parentStringTag;
nsAutoString non_const_aTag(aTag);
nsresult res = mDTD->StringTagToIntTag(non_const_aTag,&childTagEnum);
if (NS_FAILED(res)) return PR_FALSE;
nsCOMPtr<nsIDOMElement> parentElement = do_QueryInterface(aParent);
if (!parentElement) return PR_FALSE;
parentElement->GetTagName(parentStringTag);
res = mDTD->StringTagToIntTag(parentStringTag,&parentTagEnum);
return TagCanContainTag(parentStringTag, aChildTag);
}
PRBool
nsEditor::TagCanContain(const nsString &aParentTag, nsIDOMNode* aChild)
{
nsAutoString childStringTag;
nsCOMPtr<nsIDOMElement> childElement = do_QueryInterface(aChild);
if (!childElement) return PR_FALSE;
childElement->GetTagName(childStringTag);
return TagCanContainTag(aParentTag, childStringTag);
}
PRBool
nsEditor::TagCanContainTag(const nsString &aParentTag, const nsString &aChildTag)
{
// if we don't have a dtd then assume we can insert whatever want
if (!mDTD) return PR_TRUE;
PRInt32 childTagEnum, parentTagEnum;
nsAutoString non_const_childTag(aChildTag);
nsAutoString non_const_parentTag(aParentTag);
nsresult res = mDTD->StringTagToIntTag(non_const_childTag,&childTagEnum);
if (NS_FAILED(res)) return PR_FALSE;
res = mDTD->StringTagToIntTag(non_const_parentTag,&parentTagEnum);
if (NS_FAILED(res)) return PR_FALSE;
return mDTD->CanContain(parentTagEnum, childTagEnum);

View File

@ -422,7 +422,7 @@ public:
/** All editor operations which alter the doc should be followed
* with a call to EndOperation, naming the action and direction */
NS_IMETHOD EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
NS_IMETHOD EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection, PRBool aSetSelection);
/** return the string that represents text nodes in the content tree */
static nsresult GetTextNodeTag(nsString& aOutString);
@ -608,6 +608,8 @@ public:
/** returns PR_TRUE if aParent can contain a child of type aTag */
PRBool CanContainTag(nsIDOMNode* aParent, const nsString &aTag);
PRBool TagCanContain(const nsString &aParentTag, nsIDOMNode* aChild);
PRBool TagCanContainTag(const nsString &aParentTag, const nsString &aChildTag);
/** returns PR_TRUE if aNode is a container */
PRBool IsContainer(nsIDOMNode *aNode);

View File

@ -93,15 +93,16 @@ class nsAutoRules
{
public:
nsAutoRules(nsEditor *ed, PRInt32 action, nsIEditor::EDirection aDirection) :
mEd(ed), mAction(action), mDirection(aDirection)
nsAutoRules(nsEditor *ed, PRInt32 action, nsIEditor::EDirection aDirection, PRBool setSelection=PR_FALSE) :
mEd(ed), mAction(action), mDirection(aDirection), mSetSelection(setSelection)
{if (mEd) mEd->StartOperation(mAction, mDirection);}
~nsAutoRules() {if (mEd) mEd->EndOperation(mAction, mDirection);}
~nsAutoRules() {if (mEd) mEd->EndOperation(mAction, mDirection, mSetSelection);}
protected:
nsEditor *mEd;
PRInt32 mAction;
nsIEditor::EDirection mDirection;
PRBool mSetSelection;
};

View File

@ -148,7 +148,7 @@ nsHTMLEditRules::BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection)
NS_IMETHODIMP
nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection, PRBool aSetSelection)
{
if (mLockRulesSniffing) return NS_OK;
@ -172,8 +172,16 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
// expand the "changed doc range" as needed
// MOOSE: I don't do this if the aSetSelection param is true. This is because
// if aSetSelection is true, it means we are to set the selection to the changed
// document region when we are done. So I need to preserve mDocChangeRange as is.
// I should probably set up a parellel range for this purpose.
if (!aSetSelection)
{
res = PromoteRange(mDocChangeRange, action);
if (NS_FAILED(res)) return res;
}
// add in any needed <br>s, and remove any unneeded ones.
res = AdjustSpecialBreaks();
@ -208,6 +216,12 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
nsCOMPtr<nsIPresShell> pres;
mEditor->GetPresShell(getter_AddRefs(pres));
if (pres) pres->SetCaretEnabled(PR_TRUE);
if (aSetSelection)
{
selection->ClearSelection();
selection->AddRange(mDocChangeRange);
}
}
return res;
@ -1100,7 +1114,7 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
{
// 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
res = ReplaceContainer(curNode,&newBlock,blockType);
res = mEditor->ReplaceContainer(curNode,&newBlock,blockType);
if (NS_FAILED(res)) return res;
curList = newBlock;
continue;
@ -1118,7 +1132,7 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
{
// 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
ReplaceContainer(curNode,&newBlock,blockType);
mEditor->ReplaceContainer(curNode,&newBlock,blockType);
if (NS_FAILED(res)) return res;
curList = newBlock;
continue;
@ -1179,11 +1193,11 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
// don't wrap li around a paragraph. instead replace paragraph with li
if (nsHTMLEditUtils::IsParagraph(curNode))
{
res = ReplaceContainer(curNode, &listItem, "li");
res = mEditor->ReplaceContainer(curNode, &listItem, "li");
}
else
{
res = InsertContainerAbove(curNode, &listItem, "li");
res = mEditor->InsertContainerAbove(curNode, &listItem, "li");
}
if (NS_FAILED(res)) return res;
if (nsEditor::IsInlineNode(curNode))
@ -1503,7 +1517,7 @@ nsHTMLEditRules::WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel, PRBoo
{
if (nsHTMLEditUtils::IsList(curNode)) // just unwrap this sublist
{
res = RemoveContainer(curNode);
res = mEditor->RemoveContainer(curNode);
if (NS_FAILED(res)) return res;
}
else // we are moving a list item, but not whole list
@ -1547,7 +1561,7 @@ nsHTMLEditRules::WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel, PRBoo
{
if (nsHTMLEditUtils::IsBlockquote(n))
{
RemoveContainer(n);
mEditor->RemoveContainer(n);
break;
}
n->GetParentNode(getter_AddRefs(tmp));
@ -2347,142 +2361,6 @@ nsHTMLEditRules::MakeTransitionList(nsISupportsArray *inArrayOfNodes,
}
///////////////////////////////////////////////////////////////////////////
// ReplaceContainer: replace inNode with a new node (outNode) which is contructed
// to be of type aNodeType. Put inNodes children into outNode.
// Callers responsibility to make sure inNode's children can
// go in outNode.
nsresult
nsHTMLEditRules::ReplaceContainer(nsIDOMNode *inNode,
nsCOMPtr<nsIDOMNode> *outNode,
const nsString &aNodeType)
{
if (!inNode || !outNode)
return NS_ERROR_NULL_POINTER;
nsresult res;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
res = nsEditor::GetNodeLocation(inNode, &parent, &offset);
if (NS_FAILED(res)) return res;
res = mEditor->CreateNode(aNodeType, parent, offset, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
PRBool bHasMoreChildren;
inNode->HasChildNodes(&bHasMoreChildren);
nsCOMPtr<nsIDOMNode> child;
offset = 0;
while (bHasMoreChildren)
{
inNode->GetLastChild(getter_AddRefs(child));
res = mEditor->DeleteNode(child);
if (NS_FAILED(res)) return res;
res = mEditor->InsertNode(child, *outNode, 0);
if (NS_FAILED(res)) return res;
inNode->HasChildNodes(&bHasMoreChildren);
}
res = mEditor->DeleteNode(inNode);
return res;
}
///////////////////////////////////////////////////////////////////////////
// RemoveContainer: remove inNode, reparenting it's children into their
// the parent of inNode
//
nsresult
nsHTMLEditRules::RemoveContainer(nsIDOMNode *inNode, PRBool aAddBRIfNeeded)
{
if (!inNode)
return NS_ERROR_NULL_POINTER;
if (nsHTMLEditUtils::IsBody(inNode))
return NS_ERROR_UNEXPECTED;
nsresult res;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
res = nsEditor::GetNodeLocation(inNode, &parent, &offset);
if (NS_FAILED(res)) return res;
// add BR's before and/or after the inNode
// if aAddBRIfNeeded is set and if the content
// before/after the node is inline.
// Only do this if inNode is a block node.
if (aAddBRIfNeeded && mEditor->IsBlockNode(inNode))
{
nsCOMPtr<nsIDOMNode> nearNode, brNode;
res = GetPriorHTMLSibling(inNode, &nearNode);
if (NS_FAILED(res)) return res;
if (nearNode && mEditor->IsInlineNode(nearNode))
{
res = mEditor->CreateBR(parent, offset, &brNode);
if (NS_FAILED(res)) return res;
// refresh location info
res = nsEditor::GetNodeLocation(inNode, &parent, &offset);
if (NS_FAILED(res)) return res;
}
res = GetNextHTMLSibling(inNode, &nearNode);
if (NS_FAILED(res)) return res;
if (nearNode && mEditor->IsInlineNode(nearNode))
{
res = mEditor->CreateBR(parent, offset+1, &brNode);
if (NS_FAILED(res)) return res;
// refresh location info
res = nsEditor::GetNodeLocation(inNode, &parent, &offset);
if (NS_FAILED(res)) return res;
}
}
// loop through the child nodes of inNode and promote them
// into inNode's parent.
PRBool bHasMoreChildren;
inNode->HasChildNodes(&bHasMoreChildren);
nsCOMPtr<nsIDOMNode> child;
while (bHasMoreChildren)
{
inNode->GetLastChild(getter_AddRefs(child));
res = mEditor->DeleteNode(child);
if (NS_FAILED(res)) return res;
res = mEditor->InsertNode(child, parent, offset);
if (NS_FAILED(res)) return res;
inNode->HasChildNodes(&bHasMoreChildren);
}
res = mEditor->DeleteNode(inNode);
return res;
}
///////////////////////////////////////////////////////////////////////////
// InsertContainerAbove: insert a new parent for inNode, returned in outNode,
// which is contructed to be of type aNodeType. outNode becomes
// a child of inNode's earlier parent.
// Callers responsibility to make sure inNode's can be child
// of outNode, and outNode can be child of old parent.
nsresult
nsHTMLEditRules::InsertContainerAbove(nsIDOMNode *inNode,
nsCOMPtr<nsIDOMNode> *outNode,
const nsString &aNodeType)
{
if (!inNode || !outNode)
return NS_ERROR_NULL_POINTER;
nsresult res;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
res = nsEditor::GetNodeLocation(inNode, &parent, &offset);
if (NS_FAILED(res)) return res;
// make new parent, outNode
res = mEditor->CreateNode(aNodeType, parent, offset, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// put inNode in new parent, outNode
res = mEditor->DeleteNode(inNode);
if (NS_FAILED(res)) return res;
res = mEditor->InsertNode(inNode, *outNode, 0);
if (NS_FAILED(res)) return res;
return NS_OK;
}
/********************************************************
* main implementation methods
@ -2558,7 +2436,7 @@ nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection,
}
// else unwrap it
nsCOMPtr<nsIDOMNode> newBlock;
res = RemoveContainer(aHeader);
res = mEditor->RemoveContainer(aHeader);
return res;
}
@ -2958,11 +2836,11 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString
// nsCOMPtr<nsIDOMNode> brNode;
// res = mEditor->CreateBR(curParent, offset+1, &brNode);
// if (NS_FAILED(res)) return res;
res = RemoveContainer(curNode, PR_TRUE);
res = mEditor->RemoveContainer(curNode);
}
else
{
res = ReplaceContainer(curNode, &newBlock, *aBlockTag);
res = mEditor->ReplaceContainer(curNode, &newBlock, *aBlockTag);
}
if (NS_FAILED(res)) return res;
}
@ -3743,7 +3621,7 @@ nsHTMLEditRules::PopListItem(nsIDOMNode *aListItem, PRBool *aOutOfList)
nsCOMPtr<nsIDOMNode> lastChild;
res = GetLastEditableChild(curNode, &lastChild);
if (NS_FAILED(res)) return res;
res = RemoveContainer(curNode);
res = mEditor->RemoveContainer(curNode);
if (NS_FAILED(res)) return res;
if (mEditor->IsInlineNode(lastChild))
{
@ -4003,15 +3881,9 @@ nsHTMLEditListener::DidSplitNode(nsIDOMNode *aExistingRightNode,
nsresult aResult)
{
nsCOMPtr<nsIDOMRange> range;
nsresult res = MakeRangeFromNode(aNewLeftNode, &range);
if (NS_FAILED(res)) return res;
if (range)
{
// now extend range to include right node
res = range->SetEndAfter(aExistingRightNode);
nsresult res = MakeCollapsedRange(aExistingRightNode, 0, &range);
if (NS_FAILED(res)) return res;
res = mRules->UpdateDocChangeRange(range);
}
return res;
}
@ -4019,7 +3891,9 @@ nsHTMLEditListener::DidSplitNode(nsIDOMNode *aExistingRightNode,
NS_IMETHODIMP
nsHTMLEditListener::WillJoinNodes(nsIDOMNode *aLeftNode, nsIDOMNode *aRightNode, nsIDOMNode *aParent)
{
return NS_OK;
// remember split point
nsresult res = nsEditor::GetLengthOfDOMNode(aLeftNode, mJoinOffset);
return res;
}
@ -4029,14 +3903,11 @@ nsHTMLEditListener::DidJoinNodes(nsIDOMNode *aLeftNode,
nsIDOMNode *aParent,
nsresult aResult)
{
nsCOMPtr<nsIDOMRange> range;
// assumption that Join keeps the righthand node
nsresult res = MakeRangeFromNode(aRightNode, &range);
nsCOMPtr<nsIDOMRange> range;
nsresult res = MakeCollapsedRange(aRightNode, mJoinOffset, &range);
if (NS_FAILED(res)) return res;
if (range)
{
res = mRules->UpdateDocChangeRange(range);
}
return res;
}
@ -4143,6 +4014,28 @@ nsHTMLEditListener::MakeRangeFromNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMRange>
}
nsresult
nsHTMLEditListener::MakeCollapsedRange(nsIDOMNode *inNode, PRInt32 inOffset, nsCOMPtr<nsIDOMRange> *outRange)
{
if (!inNode || !outRange) return NS_ERROR_NULL_POINTER;
*outRange = nsnull;
// first check that inNode is still a descendant of the body
if (!IsDescendantOfBody(inNode)) return NS_OK;
// construct a range to represent start and end of inNode
nsresult res = nsComponentManager::CreateInstance(kRangeCID,
nsnull,
NS_GET_IID(nsIDOMRange),
getter_AddRefs(*outRange));
if (NS_FAILED(res)) return res;
res = (*outRange)->SetStart(inNode, inOffset);
if (NS_FAILED(res)) return res;
res = (*outRange)->SetEnd(inNode, inOffset);
return res;
}
nsresult
nsHTMLEditListener::MakeRangeFromTextOffsets(nsIDOMCharacterData *inNode,
PRInt32 inStart,

View File

@ -42,7 +42,7 @@ public:
// nsEditRules methods
NS_IMETHOD BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection);
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection);
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection, PRBool aSetSelection);
NS_IMETHOD Init(nsHTMLEditor *aEditor, PRUint32 aFlags);
NS_IMETHOD WillDoAction(nsIDOMSelection *aSelection, nsRulesInfo *aInfo, PRBool *aCancel, PRBool *aHandled);
NS_IMETHOD DidDoAction(nsIDOMSelection *aSelection, nsRulesInfo *aInfo, nsresult aResult);
@ -111,10 +111,6 @@ protected:
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, PRBool aAddBRIfNeeded=PR_FALSE);
nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, const nsString &aNodeType);
nsresult JoinNodesSmart( nsIDOMNode *aNodeLeft,
nsIDOMNode *aNodeRight,
nsCOMPtr<nsIDOMNode> *aOutMergeParent,
@ -189,12 +185,14 @@ protected:
PRInt32 inStart,
PRInt32 inEnd,
nsCOMPtr<nsIDOMRange> *outRange);
nsresult MakeCollapsedRange(nsIDOMNode *inNode, PRInt32 inOffset, nsCOMPtr<nsIDOMRange> *outRange);
PRBool IsDescendantOfBody(nsIDOMNode *inNode) ;
// data members
nsHTMLEditor *mEditor;
nsHTMLEditRules *mRules;
nsCOMPtr<nsIDOMNode> mBody;
PRUint32 mJoinOffset; // need to remember an int across willJoin/didJoin...
};
#endif //nsHTMLEditRules_h__

View File

@ -68,6 +68,42 @@ nsHTMLEditUtils::IsBreak(nsIDOMNode *node)
}
///////////////////////////////////////////////////////////////////////////
// IsBreak: true if node an html break node
//
PRBool
nsHTMLEditUtils::IsBig(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null node passed to nsHTMLEditUtils::IsBig");
nsAutoString tag;
nsEditor::GetTagString(node,tag);
tag.ToLowerCase();
if (tag == "big")
{
return PR_TRUE;
}
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsBreak: true if node an html break node
//
PRBool
nsHTMLEditUtils::IsSmall(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null node passed to nsHTMLEditUtils::IsSmall");
nsAutoString tag;
nsEditor::GetTagString(node,tag);
tag.ToLowerCase();
if (tag == "small")
{
return PR_TRUE;
}
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsMozBR: true if node an html br node with type = _moz
//

View File

@ -34,6 +34,8 @@ public:
// from nsTextEditRules:
static PRBool IsBody(nsIDOMNode *aNode);
static PRBool IsBreak(nsIDOMNode *aNode);
static PRBool IsBig(nsIDOMNode *aNode);
static PRBool IsSmall(nsIDOMNode *aNode);
static PRBool IsMozBR(nsIDOMNode *aNode);
static PRBool HasMozAttr(nsIDOMNode *aNode);
static PRBool InBody(nsIDOMNode *aNode);

View File

@ -102,6 +102,7 @@ static NS_DEFINE_CID(kCNavDTDCID, NS_CNAVDTD_CID);
static NS_DEFINE_CID(kHTMLEditorCID, NS_HTMLEDITOR_CID);
static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID);
static NS_DEFINE_IID(kSubtreeIteratorCID, NS_SUBTREEITERATOR_CID);
static NS_DEFINE_CID(kCRangeCID, NS_RANGE_CID);
static NS_DEFINE_IID(kFileWidgetCID, NS_FILEWIDGET_CID);
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
@ -1341,14 +1342,12 @@ NS_IMETHODIMP nsHTMLEditor::RemoveInlineProperty(nsIAtom *aProperty, const nsStr
NS_IMETHODIMP nsHTMLEditor::IncreaseFontSize()
{
//TODO: Write this!
return NS_ERROR_NOT_IMPLEMENTED;
return RelativeFontChange(1);
}
NS_IMETHODIMP nsHTMLEditor::DecreaseFontSize()
{
//TODO: Write this!
return NS_ERROR_NOT_IMPLEMENTED;
return RelativeFontChange(-1);
}
NS_IMETHODIMP nsHTMLEditor::GetTypingState(nsIAtom *aProperty, PRBool &aPropIsSet, PRBool &aSetting)
@ -4512,11 +4511,11 @@ nsHTMLEditor::StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
/** All editor operations which alter the doc should be followed
* with a call to EndOperation, naming the action and direction */
NS_IMETHODIMP
nsHTMLEditor::EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
nsHTMLEditor::EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection, PRBool aSetSelection)
{
if (! ((opID==kOpInsertText) || (opID==kOpInsertIMEText)) )
ClearInlineStylesCache();
if (mRules) return mRules->AfterEdit(opID, aDirection);
if (mRules) return mRules->AfterEdit(opID, aDirection, aSetSelection);
return NS_OK;
}
@ -7213,7 +7212,7 @@ nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMSelection *aInSelection)
{
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
nsCOMPtr<nsIContentIterator> iter;
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
result = nsComponentManager::CreateInstance(kSubtreeIteratorCID, nsnull,
NS_GET_IID(nsIContentIterator),
getter_AddRefs(iter));
if (NS_FAILED(result)) return result;
@ -7376,3 +7375,368 @@ nsHTMLEditor::GetNextElementByTagName(nsIDOMElement *aCurrentElement,
return res;
}
#ifdef XP_MAC
#pragma mark -
#endif
nsresult
nsHTMLEditor::RelativeFontChange( PRInt32 aSizeChange)
{
// Can only change font size by + or - 1
if ( !( (aSizeChange==1) || (aSizeChange==-1) ) )
return NS_ERROR_ILLEGAL_VALUE;
ForceCompositionEnd();
// wrap with txn batching, rules sniffing, and selection preservation code
nsAutoEditBatch batchIt(this);
nsAutoRules beginRulesSniffing(this, kOpSetTextProperty, nsIEditor::eNext, PR_TRUE);
// Get the selection
nsCOMPtr<nsIDOMSelection>selection;
nsresult res = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
if (!selection) return NS_ERROR_FAILURE;
// Is the selection collapsed?
PRBool bCollapsed;
res = selection->GetIsCollapsed(&bCollapsed);
if (NS_FAILED(res)) return res;
// if it's collapsed dont do anything.
// MOOSE: We should probably have typing state for this like
// we do for other things.
if (bCollapsed)
{
return NS_OK;
}
// get selection range enumerator
nsCOMPtr<nsIEnumerator> enumerator;
res = selection->GetEnumerator(getter_AddRefs(enumerator));
if (NS_FAILED(res)) return res;
if (!enumerator) return NS_ERROR_FAILURE;
// loop thru the ranges in the selection
enumerator->First();
nsCOMPtr<nsISupports> currentItem;
while ((NS_ENUMERATOR_FALSE == enumerator->IsDone()))
{
res = enumerator->CurrentItem(getter_AddRefs(currentItem));
if (NS_FAILED(res)) return res;
if (!currentItem) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
// check for easy case: both range endpoints in same text node
nsCOMPtr<nsIDOMNode> startNode, endNode;
res = range->GetStartParent(getter_AddRefs(startNode));
if (NS_FAILED(res)) return res;
res = range->GetEndParent(getter_AddRefs(endNode));
if (NS_FAILED(res)) return res;
if ((startNode == endNode) && IsTextNode(startNode))
{
PRInt32 startOffset, endOffset;
range->GetStartOffset(&startOffset);
range->GetEndOffset(&endOffset);
nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(startNode);
res = RelativeFontChangeOnTextNode(aSizeChange, nodeAsText, startOffset, endOffset);
if (NS_FAILED(res)) return res;
}
else
{
// not the easy case. range not contained in single text node.
// there are up to three phases here. There are all the nodes
// reported by the subtree iterator to be processed. And there
// are potentially a starting textnode and an ending textnode
// which are only partially contained by the range.
// lets handle the nodes reported by the iterator. These nodes
// are entirely contained in the selection range. We build up
// a list of them (since doing operations on the document during
// iteration would perturb the iterator).
nsCOMPtr<nsIContentIterator> iter;
res = nsComponentManager::CreateInstance(kSubtreeIteratorCID, nsnull,
NS_GET_IID(nsIContentIterator),
getter_AddRefs(iter));
if (NS_FAILED(res)) return res;
if (!iter) return NS_ERROR_FAILURE;
nsCOMPtr<nsISupportsArray> arrayOfNodes;
nsCOMPtr<nsIContent> content;
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsISupports> isupports;
// make a array
res = NS_NewISupportsArray(getter_AddRefs(arrayOfNodes));
if (NS_FAILED(res)) return res;
// iterate range and build up array
iter->Init(range);
while (NS_ENUMERATOR_FALSE == iter->IsDone())
{
res = iter->CurrentNode(getter_AddRefs(content));
if (NS_FAILED(res)) return res;
node = do_QueryInterface(content);
if (!node) return NS_ERROR_FAILURE;
isupports = do_QueryInterface(node);
arrayOfNodes->AppendElement(isupports);
res = iter->Next();
if (NS_FAILED(res)) return res;
}
// now that we have the list, do the font size change on each node
PRUint32 listCount;
PRInt32 j;
arrayOfNodes->Count(&listCount);
for (j = 0; j < listCount; j++)
{
isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
node = do_QueryInterface(isupports);
res = RelativeFontChangeOnNode(aSizeChange, node);
if (NS_FAILED(res)) return res;
arrayOfNodes->RemoveElementAt(0);
}
// now check the start and end parents of the range to see if they need to
// be seperately handled (they do if they are text nodes, due to how the
// subtree iterator works - it will not have reported them).
if (IsTextNode(startNode))
{
nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(startNode);
PRInt32 startOffset;
PRUint32 textLen;
range->GetStartOffset(&startOffset);
nodeAsText->GetLength(&textLen);
res = RelativeFontChangeOnTextNode(aSizeChange, nodeAsText, startOffset, textLen);
if (NS_FAILED(res)) return res;
}
if (IsTextNode(endNode))
{
nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(endNode);
PRInt32 endOffset;
range->GetEndOffset(&endOffset);
res = RelativeFontChangeOnTextNode(aSizeChange, nodeAsText, 0, endOffset);
if (NS_FAILED(res)) return res;
}
}
enumerator->Next();
}
return res;
}
nsresult
nsHTMLEditor::RelativeFontChangeOnTextNode( PRInt32 aSizeChange,
nsIDOMCharacterData *aTextNode,
PRInt32 aStartOffset,
PRInt32 aEndOffset)
{
// Can only change font size by + or - 1
if ( !( (aSizeChange==1) || (aSizeChange==-1) ) )
return NS_ERROR_ILLEGAL_VALUE;
if (!aTextNode) return NS_ERROR_NULL_POINTER;
// dont need to do anything if no characters actually selected
if (aStartOffset == aEndOffset) return NS_OK;
nsresult res = NS_OK;
nsCOMPtr<nsIDOMNode> tmp, node = do_QueryInterface(aTextNode);
// do we need to split the text node?
PRUint32 textLen;
aTextNode->GetLength(&textLen);
if ( aEndOffset != textLen )
{
// we need to split off back of text node
res = SplitNode(node, aEndOffset, getter_AddRefs(tmp));
if (NS_FAILED(res)) return res;
node = tmp; // remember left node
}
if ( aStartOffset )
{
// we need to split off front of text node
res = SplitNode(node, aStartOffset, getter_AddRefs(tmp));
if (NS_FAILED(res)) return res;
}
// reparent the node inside font node with appropriate relative size
nsAutoString tag;
if (aSizeChange == 1) tag = "big";
else tag = "small";
res = InsertContainerAbove(node, &tmp, tag);
return res;
}
nsresult
nsHTMLEditor::RelativeFontChangeOnNode( PRInt32 aSizeChange,
nsIDOMNode *aNode)
{
// Can only change font size by + or - 1
if ( !( (aSizeChange==1) || (aSizeChange==-1) ) )
return NS_ERROR_ILLEGAL_VALUE;
if (!aNode) return NS_ERROR_NULL_POINTER;
nsresult res = NS_OK;
nsCOMPtr<nsIDOMNode> tmp;
nsAutoString tag;
if (aSizeChange == 1) tag = "big";
else tag = "small";
// is this node a text node?
if (IsTextNode(aNode))
{
res = InsertContainerAbove(aNode, &tmp, tag);
return res;
}
// is it the opposite of what we want?
if ( ((aSizeChange == 1) && nsHTMLEditUtils::IsSmall(aNode)) ||
((aSizeChange == -1) && nsHTMLEditUtils::IsBig(aNode)) )
{
// in that case, just remove this node and pull up the children
res = RemoveContainer(aNode);
return res;
}
// can it be put inside a "big" or "small"?
if (TagCanContain(tag, aNode))
{
// ok, chuck it in.
res = InsertContainerAbove(aNode, &tmp, tag);
return res;
}
// none of the above? then cycle through the children.
// MOOSE: we should group the children together if possible
// into a single "big" or "small". For the moment they are
// each getting their own.
nsCOMPtr<nsIDOMNodeList> childNodes;
res = aNode->GetChildNodes(getter_AddRefs(childNodes));
if (NS_FAILED(res)) return res;
if (childNodes)
{
PRInt32 j;
PRUint32 childCount;
childNodes->GetLength(&childCount);
for (j=0 ; j<childCount; j++)
{
nsCOMPtr<nsIDOMNode> childNode;
res = childNodes->Item(j, getter_AddRefs(childNode));
if ((NS_SUCCEEDED(res)) && (childNode))
{
res = RelativeFontChangeOnNode(aSizeChange, childNode);
if (NS_FAILED(res)) return res;
}
}
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// ReplaceContainer: replace inNode with a new node (outNode) which is contructed
// to be of type aNodeType. Put inNodes children into outNode.
// Callers responsibility to make sure inNode's children can
// go in outNode.
nsresult
nsHTMLEditor::ReplaceContainer(nsIDOMNode *inNode,
nsCOMPtr<nsIDOMNode> *outNode,
const nsString &aNodeType)
{
if (!inNode || !outNode)
return NS_ERROR_NULL_POINTER;
nsresult res;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
res = GetNodeLocation(inNode, &parent, &offset);
if (NS_FAILED(res)) return res;
res = CreateNode(aNodeType, parent, offset, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
PRBool bHasMoreChildren;
inNode->HasChildNodes(&bHasMoreChildren);
nsCOMPtr<nsIDOMNode> child;
offset = 0;
while (bHasMoreChildren)
{
inNode->GetLastChild(getter_AddRefs(child));
res = DeleteNode(child);
if (NS_FAILED(res)) return res;
res = InsertNode(child, *outNode, 0);
if (NS_FAILED(res)) return res;
inNode->HasChildNodes(&bHasMoreChildren);
}
res = DeleteNode(inNode);
return res;
}
///////////////////////////////////////////////////////////////////////////
// RemoveContainer: remove inNode, reparenting it's children into their
// the parent of inNode
//
nsresult
nsHTMLEditor::RemoveContainer(nsIDOMNode *inNode)
{
if (!inNode)
return NS_ERROR_NULL_POINTER;
if (nsHTMLEditUtils::IsBody(inNode))
return NS_ERROR_UNEXPECTED;
nsresult res;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
res = GetNodeLocation(inNode, &parent, &offset);
if (NS_FAILED(res)) return res;
// loop through the child nodes of inNode and promote them
// into inNode's parent.
PRBool bHasMoreChildren;
inNode->HasChildNodes(&bHasMoreChildren);
nsCOMPtr<nsIDOMNode> child;
while (bHasMoreChildren)
{
inNode->GetLastChild(getter_AddRefs(child));
res = DeleteNode(child);
if (NS_FAILED(res)) return res;
res = InsertNode(child, parent, offset);
if (NS_FAILED(res)) return res;
inNode->HasChildNodes(&bHasMoreChildren);
}
res = DeleteNode(inNode);
return res;
}
///////////////////////////////////////////////////////////////////////////
// InsertContainerAbove: insert a new parent for inNode, returned in outNode,
// which is contructed to be of type aNodeType. outNode becomes
// a child of inNode's earlier parent.
// Callers responsibility to make sure inNode's can be child
// of outNode, and outNode can be child of old parent.
nsresult
nsHTMLEditor::InsertContainerAbove(nsIDOMNode *inNode,
nsCOMPtr<nsIDOMNode> *outNode,
const nsString &aNodeType)
{
if (!inNode || !outNode)
return NS_ERROR_NULL_POINTER;
nsresult res;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
res = GetNodeLocation(inNode, &parent, &offset);
if (NS_FAILED(res)) return res;
// make new parent, outNode
res = CreateNode(aNodeType, parent, offset, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// put inNode in new parent, outNode
res = DeleteNode(inNode);
if (NS_FAILED(res)) return res;
res = InsertNode(inNode, *outNode, 0);
if (NS_FAILED(res)) return res;
return NS_OK;
}

View File

@ -260,7 +260,7 @@ public:
/** All editor operations which alter the doc should be followed
* with a call to EndOperation, naming the action and direction */
NS_IMETHOD EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
NS_IMETHOD EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection, PRBool aSetSelection);
/** returns PR_TRUE if aParent can contain a child of type aTag */
PRBool CanContainTag(nsIDOMNode* aParent, const nsString &aTag);
@ -546,6 +546,23 @@ protected:
/* small utility routine to test the eEditorReadonly bit */
PRBool IsModifiable();
/* increase/decrease the font size of selection */
nsresult RelativeFontChange( PRInt32 aSizeChange);
/* helper routines for font size changing */
nsresult RelativeFontChangeOnTextNode( PRInt32 aSizeChange,
nsIDOMCharacterData *aTextNode,
PRInt32 aStartOffset,
PRInt32 aEndOffset);
nsresult RelativeFontChangeOnNode( PRInt32 aSizeChange,
nsIDOMNode *aNode);
/* helper routines for node/parent manipulations */
nsresult ReplaceContainer(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, const nsString &aNodeType);
nsresult RemoveContainer(nsIDOMNode *inNode);
nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, const nsString &aNodeType);
// Data members
protected:

View File

@ -150,7 +150,7 @@ nsTextEditRules::BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection)
NS_IMETHODIMP
nsTextEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
nsTextEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection, PRBool aSetSelection)
{
if (mLockRulesSniffing) return NS_OK;

View File

@ -52,7 +52,7 @@ public:
// nsEditRules methods
NS_IMETHOD Init(nsHTMLEditor *aEditor, PRUint32 aFlags);
NS_IMETHOD BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection);
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection);
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection, PRBool aSetSelection);
NS_IMETHOD WillDoAction(nsIDOMSelection *aSelection, nsRulesInfo *aInfo, PRBool *aCancel, PRBool *aHandled);
NS_IMETHOD DidDoAction(nsIDOMSelection *aSelection, nsRulesInfo *aInfo, nsresult aResult);
NS_IMETHOD GetFlags(PRUint32 *aFlags);

View File

@ -49,7 +49,7 @@ class nsEditRules
public:
NS_IMETHOD Init(nsHTMLEditor *aEditor, PRUint32 aFlags)=0;
NS_IMETHOD BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection)=0;
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)=0;
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection, PRBool aSetSelection)=0;
NS_IMETHOD WillDoAction(nsIDOMSelection *aSelection, nsRulesInfo *aInfo, PRBool *aCancel, PRBool *aHandled)=0;
NS_IMETHOD DidDoAction(nsIDOMSelection *aSelection, nsRulesInfo *aInfo, nsresult aResult)=0;
NS_IMETHOD GetFlags(PRUint32 *aFlags)=0;

View File

@ -1787,7 +1787,7 @@ nsEditor::StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
/** All editor operations which alter the doc should be followed
* with a call to EndOperation, naming the action and direction */
NS_IMETHODIMP
nsEditor::EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
nsEditor::EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection, PRBool aSetSelection)
{
return NS_OK;
}
@ -3304,22 +3304,41 @@ nsEditor::NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag)
}
PRBool
nsEditor::CanContainTag(nsIDOMNode* aParent, const nsString &aTag)
nsEditor::CanContainTag(nsIDOMNode* aParent, const nsString &aChildTag)
{
// if we don't have a dtd then assume we can insert whatever want
if (!mDTD) return PR_TRUE;
PRInt32 childTagEnum, parentTagEnum;
nsAutoString parentStringTag;
nsAutoString non_const_aTag(aTag);
nsresult res = mDTD->StringTagToIntTag(non_const_aTag,&childTagEnum);
if (NS_FAILED(res)) return PR_FALSE;
nsCOMPtr<nsIDOMElement> parentElement = do_QueryInterface(aParent);
if (!parentElement) return PR_FALSE;
parentElement->GetTagName(parentStringTag);
res = mDTD->StringTagToIntTag(parentStringTag,&parentTagEnum);
return TagCanContainTag(parentStringTag, aChildTag);
}
PRBool
nsEditor::TagCanContain(const nsString &aParentTag, nsIDOMNode* aChild)
{
nsAutoString childStringTag;
nsCOMPtr<nsIDOMElement> childElement = do_QueryInterface(aChild);
if (!childElement) return PR_FALSE;
childElement->GetTagName(childStringTag);
return TagCanContainTag(aParentTag, childStringTag);
}
PRBool
nsEditor::TagCanContainTag(const nsString &aParentTag, const nsString &aChildTag)
{
// if we don't have a dtd then assume we can insert whatever want
if (!mDTD) return PR_TRUE;
PRInt32 childTagEnum, parentTagEnum;
nsAutoString non_const_childTag(aChildTag);
nsAutoString non_const_parentTag(aParentTag);
nsresult res = mDTD->StringTagToIntTag(non_const_childTag,&childTagEnum);
if (NS_FAILED(res)) return PR_FALSE;
res = mDTD->StringTagToIntTag(non_const_parentTag,&parentTagEnum);
if (NS_FAILED(res)) return PR_FALSE;
return mDTD->CanContain(parentTagEnum, childTagEnum);

View File

@ -422,7 +422,7 @@ public:
/** All editor operations which alter the doc should be followed
* with a call to EndOperation, naming the action and direction */
NS_IMETHOD EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
NS_IMETHOD EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection, PRBool aSetSelection);
/** return the string that represents text nodes in the content tree */
static nsresult GetTextNodeTag(nsString& aOutString);
@ -608,6 +608,8 @@ public:
/** returns PR_TRUE if aParent can contain a child of type aTag */
PRBool CanContainTag(nsIDOMNode* aParent, const nsString &aTag);
PRBool TagCanContain(const nsString &aParentTag, nsIDOMNode* aChild);
PRBool TagCanContainTag(const nsString &aParentTag, const nsString &aChildTag);
/** returns PR_TRUE if aNode is a container */
PRBool IsContainer(nsIDOMNode *aNode);

View File

@ -93,15 +93,16 @@ class nsAutoRules
{
public:
nsAutoRules(nsEditor *ed, PRInt32 action, nsIEditor::EDirection aDirection) :
mEd(ed), mAction(action), mDirection(aDirection)
nsAutoRules(nsEditor *ed, PRInt32 action, nsIEditor::EDirection aDirection, PRBool setSelection=PR_FALSE) :
mEd(ed), mAction(action), mDirection(aDirection), mSetSelection(setSelection)
{if (mEd) mEd->StartOperation(mAction, mDirection);}
~nsAutoRules() {if (mEd) mEd->EndOperation(mAction, mDirection);}
~nsAutoRules() {if (mEd) mEd->EndOperation(mAction, mDirection, mSetSelection);}
protected:
nsEditor *mEd;
PRInt32 mAction;
nsIEditor::EDirection mDirection;
PRBool mSetSelection;
};

View File

@ -148,7 +148,7 @@ nsHTMLEditRules::BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection)
NS_IMETHODIMP
nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection, PRBool aSetSelection)
{
if (mLockRulesSniffing) return NS_OK;
@ -172,8 +172,16 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
// expand the "changed doc range" as needed
// MOOSE: I don't do this if the aSetSelection param is true. This is because
// if aSetSelection is true, it means we are to set the selection to the changed
// document region when we are done. So I need to preserve mDocChangeRange as is.
// I should probably set up a parellel range for this purpose.
if (!aSetSelection)
{
res = PromoteRange(mDocChangeRange, action);
if (NS_FAILED(res)) return res;
}
// add in any needed <br>s, and remove any unneeded ones.
res = AdjustSpecialBreaks();
@ -208,6 +216,12 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
nsCOMPtr<nsIPresShell> pres;
mEditor->GetPresShell(getter_AddRefs(pres));
if (pres) pres->SetCaretEnabled(PR_TRUE);
if (aSetSelection)
{
selection->ClearSelection();
selection->AddRange(mDocChangeRange);
}
}
return res;
@ -1100,7 +1114,7 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
{
// 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
res = ReplaceContainer(curNode,&newBlock,blockType);
res = mEditor->ReplaceContainer(curNode,&newBlock,blockType);
if (NS_FAILED(res)) return res;
curList = newBlock;
continue;
@ -1118,7 +1132,7 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
{
// 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
ReplaceContainer(curNode,&newBlock,blockType);
mEditor->ReplaceContainer(curNode,&newBlock,blockType);
if (NS_FAILED(res)) return res;
curList = newBlock;
continue;
@ -1179,11 +1193,11 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
// don't wrap li around a paragraph. instead replace paragraph with li
if (nsHTMLEditUtils::IsParagraph(curNode))
{
res = ReplaceContainer(curNode, &listItem, "li");
res = mEditor->ReplaceContainer(curNode, &listItem, "li");
}
else
{
res = InsertContainerAbove(curNode, &listItem, "li");
res = mEditor->InsertContainerAbove(curNode, &listItem, "li");
}
if (NS_FAILED(res)) return res;
if (nsEditor::IsInlineNode(curNode))
@ -1503,7 +1517,7 @@ nsHTMLEditRules::WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel, PRBoo
{
if (nsHTMLEditUtils::IsList(curNode)) // just unwrap this sublist
{
res = RemoveContainer(curNode);
res = mEditor->RemoveContainer(curNode);
if (NS_FAILED(res)) return res;
}
else // we are moving a list item, but not whole list
@ -1547,7 +1561,7 @@ nsHTMLEditRules::WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel, PRBoo
{
if (nsHTMLEditUtils::IsBlockquote(n))
{
RemoveContainer(n);
mEditor->RemoveContainer(n);
break;
}
n->GetParentNode(getter_AddRefs(tmp));
@ -2347,142 +2361,6 @@ nsHTMLEditRules::MakeTransitionList(nsISupportsArray *inArrayOfNodes,
}
///////////////////////////////////////////////////////////////////////////
// ReplaceContainer: replace inNode with a new node (outNode) which is contructed
// to be of type aNodeType. Put inNodes children into outNode.
// Callers responsibility to make sure inNode's children can
// go in outNode.
nsresult
nsHTMLEditRules::ReplaceContainer(nsIDOMNode *inNode,
nsCOMPtr<nsIDOMNode> *outNode,
const nsString &aNodeType)
{
if (!inNode || !outNode)
return NS_ERROR_NULL_POINTER;
nsresult res;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
res = nsEditor::GetNodeLocation(inNode, &parent, &offset);
if (NS_FAILED(res)) return res;
res = mEditor->CreateNode(aNodeType, parent, offset, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
PRBool bHasMoreChildren;
inNode->HasChildNodes(&bHasMoreChildren);
nsCOMPtr<nsIDOMNode> child;
offset = 0;
while (bHasMoreChildren)
{
inNode->GetLastChild(getter_AddRefs(child));
res = mEditor->DeleteNode(child);
if (NS_FAILED(res)) return res;
res = mEditor->InsertNode(child, *outNode, 0);
if (NS_FAILED(res)) return res;
inNode->HasChildNodes(&bHasMoreChildren);
}
res = mEditor->DeleteNode(inNode);
return res;
}
///////////////////////////////////////////////////////////////////////////
// RemoveContainer: remove inNode, reparenting it's children into their
// the parent of inNode
//
nsresult
nsHTMLEditRules::RemoveContainer(nsIDOMNode *inNode, PRBool aAddBRIfNeeded)
{
if (!inNode)
return NS_ERROR_NULL_POINTER;
if (nsHTMLEditUtils::IsBody(inNode))
return NS_ERROR_UNEXPECTED;
nsresult res;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
res = nsEditor::GetNodeLocation(inNode, &parent, &offset);
if (NS_FAILED(res)) return res;
// add BR's before and/or after the inNode
// if aAddBRIfNeeded is set and if the content
// before/after the node is inline.
// Only do this if inNode is a block node.
if (aAddBRIfNeeded && mEditor->IsBlockNode(inNode))
{
nsCOMPtr<nsIDOMNode> nearNode, brNode;
res = GetPriorHTMLSibling(inNode, &nearNode);
if (NS_FAILED(res)) return res;
if (nearNode && mEditor->IsInlineNode(nearNode))
{
res = mEditor->CreateBR(parent, offset, &brNode);
if (NS_FAILED(res)) return res;
// refresh location info
res = nsEditor::GetNodeLocation(inNode, &parent, &offset);
if (NS_FAILED(res)) return res;
}
res = GetNextHTMLSibling(inNode, &nearNode);
if (NS_FAILED(res)) return res;
if (nearNode && mEditor->IsInlineNode(nearNode))
{
res = mEditor->CreateBR(parent, offset+1, &brNode);
if (NS_FAILED(res)) return res;
// refresh location info
res = nsEditor::GetNodeLocation(inNode, &parent, &offset);
if (NS_FAILED(res)) return res;
}
}
// loop through the child nodes of inNode and promote them
// into inNode's parent.
PRBool bHasMoreChildren;
inNode->HasChildNodes(&bHasMoreChildren);
nsCOMPtr<nsIDOMNode> child;
while (bHasMoreChildren)
{
inNode->GetLastChild(getter_AddRefs(child));
res = mEditor->DeleteNode(child);
if (NS_FAILED(res)) return res;
res = mEditor->InsertNode(child, parent, offset);
if (NS_FAILED(res)) return res;
inNode->HasChildNodes(&bHasMoreChildren);
}
res = mEditor->DeleteNode(inNode);
return res;
}
///////////////////////////////////////////////////////////////////////////
// InsertContainerAbove: insert a new parent for inNode, returned in outNode,
// which is contructed to be of type aNodeType. outNode becomes
// a child of inNode's earlier parent.
// Callers responsibility to make sure inNode's can be child
// of outNode, and outNode can be child of old parent.
nsresult
nsHTMLEditRules::InsertContainerAbove(nsIDOMNode *inNode,
nsCOMPtr<nsIDOMNode> *outNode,
const nsString &aNodeType)
{
if (!inNode || !outNode)
return NS_ERROR_NULL_POINTER;
nsresult res;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
res = nsEditor::GetNodeLocation(inNode, &parent, &offset);
if (NS_FAILED(res)) return res;
// make new parent, outNode
res = mEditor->CreateNode(aNodeType, parent, offset, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// put inNode in new parent, outNode
res = mEditor->DeleteNode(inNode);
if (NS_FAILED(res)) return res;
res = mEditor->InsertNode(inNode, *outNode, 0);
if (NS_FAILED(res)) return res;
return NS_OK;
}
/********************************************************
* main implementation methods
@ -2558,7 +2436,7 @@ nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection,
}
// else unwrap it
nsCOMPtr<nsIDOMNode> newBlock;
res = RemoveContainer(aHeader);
res = mEditor->RemoveContainer(aHeader);
return res;
}
@ -2958,11 +2836,11 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString
// nsCOMPtr<nsIDOMNode> brNode;
// res = mEditor->CreateBR(curParent, offset+1, &brNode);
// if (NS_FAILED(res)) return res;
res = RemoveContainer(curNode, PR_TRUE);
res = mEditor->RemoveContainer(curNode);
}
else
{
res = ReplaceContainer(curNode, &newBlock, *aBlockTag);
res = mEditor->ReplaceContainer(curNode, &newBlock, *aBlockTag);
}
if (NS_FAILED(res)) return res;
}
@ -3743,7 +3621,7 @@ nsHTMLEditRules::PopListItem(nsIDOMNode *aListItem, PRBool *aOutOfList)
nsCOMPtr<nsIDOMNode> lastChild;
res = GetLastEditableChild(curNode, &lastChild);
if (NS_FAILED(res)) return res;
res = RemoveContainer(curNode);
res = mEditor->RemoveContainer(curNode);
if (NS_FAILED(res)) return res;
if (mEditor->IsInlineNode(lastChild))
{
@ -4003,15 +3881,9 @@ nsHTMLEditListener::DidSplitNode(nsIDOMNode *aExistingRightNode,
nsresult aResult)
{
nsCOMPtr<nsIDOMRange> range;
nsresult res = MakeRangeFromNode(aNewLeftNode, &range);
if (NS_FAILED(res)) return res;
if (range)
{
// now extend range to include right node
res = range->SetEndAfter(aExistingRightNode);
nsresult res = MakeCollapsedRange(aExistingRightNode, 0, &range);
if (NS_FAILED(res)) return res;
res = mRules->UpdateDocChangeRange(range);
}
return res;
}
@ -4019,7 +3891,9 @@ nsHTMLEditListener::DidSplitNode(nsIDOMNode *aExistingRightNode,
NS_IMETHODIMP
nsHTMLEditListener::WillJoinNodes(nsIDOMNode *aLeftNode, nsIDOMNode *aRightNode, nsIDOMNode *aParent)
{
return NS_OK;
// remember split point
nsresult res = nsEditor::GetLengthOfDOMNode(aLeftNode, mJoinOffset);
return res;
}
@ -4029,14 +3903,11 @@ nsHTMLEditListener::DidJoinNodes(nsIDOMNode *aLeftNode,
nsIDOMNode *aParent,
nsresult aResult)
{
nsCOMPtr<nsIDOMRange> range;
// assumption that Join keeps the righthand node
nsresult res = MakeRangeFromNode(aRightNode, &range);
nsCOMPtr<nsIDOMRange> range;
nsresult res = MakeCollapsedRange(aRightNode, mJoinOffset, &range);
if (NS_FAILED(res)) return res;
if (range)
{
res = mRules->UpdateDocChangeRange(range);
}
return res;
}
@ -4143,6 +4014,28 @@ nsHTMLEditListener::MakeRangeFromNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMRange>
}
nsresult
nsHTMLEditListener::MakeCollapsedRange(nsIDOMNode *inNode, PRInt32 inOffset, nsCOMPtr<nsIDOMRange> *outRange)
{
if (!inNode || !outRange) return NS_ERROR_NULL_POINTER;
*outRange = nsnull;
// first check that inNode is still a descendant of the body
if (!IsDescendantOfBody(inNode)) return NS_OK;
// construct a range to represent start and end of inNode
nsresult res = nsComponentManager::CreateInstance(kRangeCID,
nsnull,
NS_GET_IID(nsIDOMRange),
getter_AddRefs(*outRange));
if (NS_FAILED(res)) return res;
res = (*outRange)->SetStart(inNode, inOffset);
if (NS_FAILED(res)) return res;
res = (*outRange)->SetEnd(inNode, inOffset);
return res;
}
nsresult
nsHTMLEditListener::MakeRangeFromTextOffsets(nsIDOMCharacterData *inNode,
PRInt32 inStart,

View File

@ -42,7 +42,7 @@ public:
// nsEditRules methods
NS_IMETHOD BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection);
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection);
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection, PRBool aSetSelection);
NS_IMETHOD Init(nsHTMLEditor *aEditor, PRUint32 aFlags);
NS_IMETHOD WillDoAction(nsIDOMSelection *aSelection, nsRulesInfo *aInfo, PRBool *aCancel, PRBool *aHandled);
NS_IMETHOD DidDoAction(nsIDOMSelection *aSelection, nsRulesInfo *aInfo, nsresult aResult);
@ -111,10 +111,6 @@ protected:
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, PRBool aAddBRIfNeeded=PR_FALSE);
nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, const nsString &aNodeType);
nsresult JoinNodesSmart( nsIDOMNode *aNodeLeft,
nsIDOMNode *aNodeRight,
nsCOMPtr<nsIDOMNode> *aOutMergeParent,
@ -189,12 +185,14 @@ protected:
PRInt32 inStart,
PRInt32 inEnd,
nsCOMPtr<nsIDOMRange> *outRange);
nsresult MakeCollapsedRange(nsIDOMNode *inNode, PRInt32 inOffset, nsCOMPtr<nsIDOMRange> *outRange);
PRBool IsDescendantOfBody(nsIDOMNode *inNode) ;
// data members
nsHTMLEditor *mEditor;
nsHTMLEditRules *mRules;
nsCOMPtr<nsIDOMNode> mBody;
PRUint32 mJoinOffset; // need to remember an int across willJoin/didJoin...
};
#endif //nsHTMLEditRules_h__

View File

@ -68,6 +68,42 @@ nsHTMLEditUtils::IsBreak(nsIDOMNode *node)
}
///////////////////////////////////////////////////////////////////////////
// IsBreak: true if node an html break node
//
PRBool
nsHTMLEditUtils::IsBig(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null node passed to nsHTMLEditUtils::IsBig");
nsAutoString tag;
nsEditor::GetTagString(node,tag);
tag.ToLowerCase();
if (tag == "big")
{
return PR_TRUE;
}
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsBreak: true if node an html break node
//
PRBool
nsHTMLEditUtils::IsSmall(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null node passed to nsHTMLEditUtils::IsSmall");
nsAutoString tag;
nsEditor::GetTagString(node,tag);
tag.ToLowerCase();
if (tag == "small")
{
return PR_TRUE;
}
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsMozBR: true if node an html br node with type = _moz
//

View File

@ -34,6 +34,8 @@ public:
// from nsTextEditRules:
static PRBool IsBody(nsIDOMNode *aNode);
static PRBool IsBreak(nsIDOMNode *aNode);
static PRBool IsBig(nsIDOMNode *aNode);
static PRBool IsSmall(nsIDOMNode *aNode);
static PRBool IsMozBR(nsIDOMNode *aNode);
static PRBool HasMozAttr(nsIDOMNode *aNode);
static PRBool InBody(nsIDOMNode *aNode);

View File

@ -102,6 +102,7 @@ static NS_DEFINE_CID(kCNavDTDCID, NS_CNAVDTD_CID);
static NS_DEFINE_CID(kHTMLEditorCID, NS_HTMLEDITOR_CID);
static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID);
static NS_DEFINE_IID(kSubtreeIteratorCID, NS_SUBTREEITERATOR_CID);
static NS_DEFINE_CID(kCRangeCID, NS_RANGE_CID);
static NS_DEFINE_IID(kFileWidgetCID, NS_FILEWIDGET_CID);
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
@ -1341,14 +1342,12 @@ NS_IMETHODIMP nsHTMLEditor::RemoveInlineProperty(nsIAtom *aProperty, const nsStr
NS_IMETHODIMP nsHTMLEditor::IncreaseFontSize()
{
//TODO: Write this!
return NS_ERROR_NOT_IMPLEMENTED;
return RelativeFontChange(1);
}
NS_IMETHODIMP nsHTMLEditor::DecreaseFontSize()
{
//TODO: Write this!
return NS_ERROR_NOT_IMPLEMENTED;
return RelativeFontChange(-1);
}
NS_IMETHODIMP nsHTMLEditor::GetTypingState(nsIAtom *aProperty, PRBool &aPropIsSet, PRBool &aSetting)
@ -4512,11 +4511,11 @@ nsHTMLEditor::StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
/** All editor operations which alter the doc should be followed
* with a call to EndOperation, naming the action and direction */
NS_IMETHODIMP
nsHTMLEditor::EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
nsHTMLEditor::EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection, PRBool aSetSelection)
{
if (! ((opID==kOpInsertText) || (opID==kOpInsertIMEText)) )
ClearInlineStylesCache();
if (mRules) return mRules->AfterEdit(opID, aDirection);
if (mRules) return mRules->AfterEdit(opID, aDirection, aSetSelection);
return NS_OK;
}
@ -7213,7 +7212,7 @@ nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMSelection *aInSelection)
{
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
nsCOMPtr<nsIContentIterator> iter;
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
result = nsComponentManager::CreateInstance(kSubtreeIteratorCID, nsnull,
NS_GET_IID(nsIContentIterator),
getter_AddRefs(iter));
if (NS_FAILED(result)) return result;
@ -7376,3 +7375,368 @@ nsHTMLEditor::GetNextElementByTagName(nsIDOMElement *aCurrentElement,
return res;
}
#ifdef XP_MAC
#pragma mark -
#endif
nsresult
nsHTMLEditor::RelativeFontChange( PRInt32 aSizeChange)
{
// Can only change font size by + or - 1
if ( !( (aSizeChange==1) || (aSizeChange==-1) ) )
return NS_ERROR_ILLEGAL_VALUE;
ForceCompositionEnd();
// wrap with txn batching, rules sniffing, and selection preservation code
nsAutoEditBatch batchIt(this);
nsAutoRules beginRulesSniffing(this, kOpSetTextProperty, nsIEditor::eNext, PR_TRUE);
// Get the selection
nsCOMPtr<nsIDOMSelection>selection;
nsresult res = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
if (!selection) return NS_ERROR_FAILURE;
// Is the selection collapsed?
PRBool bCollapsed;
res = selection->GetIsCollapsed(&bCollapsed);
if (NS_FAILED(res)) return res;
// if it's collapsed dont do anything.
// MOOSE: We should probably have typing state for this like
// we do for other things.
if (bCollapsed)
{
return NS_OK;
}
// get selection range enumerator
nsCOMPtr<nsIEnumerator> enumerator;
res = selection->GetEnumerator(getter_AddRefs(enumerator));
if (NS_FAILED(res)) return res;
if (!enumerator) return NS_ERROR_FAILURE;
// loop thru the ranges in the selection
enumerator->First();
nsCOMPtr<nsISupports> currentItem;
while ((NS_ENUMERATOR_FALSE == enumerator->IsDone()))
{
res = enumerator->CurrentItem(getter_AddRefs(currentItem));
if (NS_FAILED(res)) return res;
if (!currentItem) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
// check for easy case: both range endpoints in same text node
nsCOMPtr<nsIDOMNode> startNode, endNode;
res = range->GetStartParent(getter_AddRefs(startNode));
if (NS_FAILED(res)) return res;
res = range->GetEndParent(getter_AddRefs(endNode));
if (NS_FAILED(res)) return res;
if ((startNode == endNode) && IsTextNode(startNode))
{
PRInt32 startOffset, endOffset;
range->GetStartOffset(&startOffset);
range->GetEndOffset(&endOffset);
nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(startNode);
res = RelativeFontChangeOnTextNode(aSizeChange, nodeAsText, startOffset, endOffset);
if (NS_FAILED(res)) return res;
}
else
{
// not the easy case. range not contained in single text node.
// there are up to three phases here. There are all the nodes
// reported by the subtree iterator to be processed. And there
// are potentially a starting textnode and an ending textnode
// which are only partially contained by the range.
// lets handle the nodes reported by the iterator. These nodes
// are entirely contained in the selection range. We build up
// a list of them (since doing operations on the document during
// iteration would perturb the iterator).
nsCOMPtr<nsIContentIterator> iter;
res = nsComponentManager::CreateInstance(kSubtreeIteratorCID, nsnull,
NS_GET_IID(nsIContentIterator),
getter_AddRefs(iter));
if (NS_FAILED(res)) return res;
if (!iter) return NS_ERROR_FAILURE;
nsCOMPtr<nsISupportsArray> arrayOfNodes;
nsCOMPtr<nsIContent> content;
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsISupports> isupports;
// make a array
res = NS_NewISupportsArray(getter_AddRefs(arrayOfNodes));
if (NS_FAILED(res)) return res;
// iterate range and build up array
iter->Init(range);
while (NS_ENUMERATOR_FALSE == iter->IsDone())
{
res = iter->CurrentNode(getter_AddRefs(content));
if (NS_FAILED(res)) return res;
node = do_QueryInterface(content);
if (!node) return NS_ERROR_FAILURE;
isupports = do_QueryInterface(node);
arrayOfNodes->AppendElement(isupports);
res = iter->Next();
if (NS_FAILED(res)) return res;
}
// now that we have the list, do the font size change on each node
PRUint32 listCount;
PRInt32 j;
arrayOfNodes->Count(&listCount);
for (j = 0; j < listCount; j++)
{
isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
node = do_QueryInterface(isupports);
res = RelativeFontChangeOnNode(aSizeChange, node);
if (NS_FAILED(res)) return res;
arrayOfNodes->RemoveElementAt(0);
}
// now check the start and end parents of the range to see if they need to
// be seperately handled (they do if they are text nodes, due to how the
// subtree iterator works - it will not have reported them).
if (IsTextNode(startNode))
{
nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(startNode);
PRInt32 startOffset;
PRUint32 textLen;
range->GetStartOffset(&startOffset);
nodeAsText->GetLength(&textLen);
res = RelativeFontChangeOnTextNode(aSizeChange, nodeAsText, startOffset, textLen);
if (NS_FAILED(res)) return res;
}
if (IsTextNode(endNode))
{
nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(endNode);
PRInt32 endOffset;
range->GetEndOffset(&endOffset);
res = RelativeFontChangeOnTextNode(aSizeChange, nodeAsText, 0, endOffset);
if (NS_FAILED(res)) return res;
}
}
enumerator->Next();
}
return res;
}
nsresult
nsHTMLEditor::RelativeFontChangeOnTextNode( PRInt32 aSizeChange,
nsIDOMCharacterData *aTextNode,
PRInt32 aStartOffset,
PRInt32 aEndOffset)
{
// Can only change font size by + or - 1
if ( !( (aSizeChange==1) || (aSizeChange==-1) ) )
return NS_ERROR_ILLEGAL_VALUE;
if (!aTextNode) return NS_ERROR_NULL_POINTER;
// dont need to do anything if no characters actually selected
if (aStartOffset == aEndOffset) return NS_OK;
nsresult res = NS_OK;
nsCOMPtr<nsIDOMNode> tmp, node = do_QueryInterface(aTextNode);
// do we need to split the text node?
PRUint32 textLen;
aTextNode->GetLength(&textLen);
if ( aEndOffset != textLen )
{
// we need to split off back of text node
res = SplitNode(node, aEndOffset, getter_AddRefs(tmp));
if (NS_FAILED(res)) return res;
node = tmp; // remember left node
}
if ( aStartOffset )
{
// we need to split off front of text node
res = SplitNode(node, aStartOffset, getter_AddRefs(tmp));
if (NS_FAILED(res)) return res;
}
// reparent the node inside font node with appropriate relative size
nsAutoString tag;
if (aSizeChange == 1) tag = "big";
else tag = "small";
res = InsertContainerAbove(node, &tmp, tag);
return res;
}
nsresult
nsHTMLEditor::RelativeFontChangeOnNode( PRInt32 aSizeChange,
nsIDOMNode *aNode)
{
// Can only change font size by + or - 1
if ( !( (aSizeChange==1) || (aSizeChange==-1) ) )
return NS_ERROR_ILLEGAL_VALUE;
if (!aNode) return NS_ERROR_NULL_POINTER;
nsresult res = NS_OK;
nsCOMPtr<nsIDOMNode> tmp;
nsAutoString tag;
if (aSizeChange == 1) tag = "big";
else tag = "small";
// is this node a text node?
if (IsTextNode(aNode))
{
res = InsertContainerAbove(aNode, &tmp, tag);
return res;
}
// is it the opposite of what we want?
if ( ((aSizeChange == 1) && nsHTMLEditUtils::IsSmall(aNode)) ||
((aSizeChange == -1) && nsHTMLEditUtils::IsBig(aNode)) )
{
// in that case, just remove this node and pull up the children
res = RemoveContainer(aNode);
return res;
}
// can it be put inside a "big" or "small"?
if (TagCanContain(tag, aNode))
{
// ok, chuck it in.
res = InsertContainerAbove(aNode, &tmp, tag);
return res;
}
// none of the above? then cycle through the children.
// MOOSE: we should group the children together if possible
// into a single "big" or "small". For the moment they are
// each getting their own.
nsCOMPtr<nsIDOMNodeList> childNodes;
res = aNode->GetChildNodes(getter_AddRefs(childNodes));
if (NS_FAILED(res)) return res;
if (childNodes)
{
PRInt32 j;
PRUint32 childCount;
childNodes->GetLength(&childCount);
for (j=0 ; j<childCount; j++)
{
nsCOMPtr<nsIDOMNode> childNode;
res = childNodes->Item(j, getter_AddRefs(childNode));
if ((NS_SUCCEEDED(res)) && (childNode))
{
res = RelativeFontChangeOnNode(aSizeChange, childNode);
if (NS_FAILED(res)) return res;
}
}
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// ReplaceContainer: replace inNode with a new node (outNode) which is contructed
// to be of type aNodeType. Put inNodes children into outNode.
// Callers responsibility to make sure inNode's children can
// go in outNode.
nsresult
nsHTMLEditor::ReplaceContainer(nsIDOMNode *inNode,
nsCOMPtr<nsIDOMNode> *outNode,
const nsString &aNodeType)
{
if (!inNode || !outNode)
return NS_ERROR_NULL_POINTER;
nsresult res;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
res = GetNodeLocation(inNode, &parent, &offset);
if (NS_FAILED(res)) return res;
res = CreateNode(aNodeType, parent, offset, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
PRBool bHasMoreChildren;
inNode->HasChildNodes(&bHasMoreChildren);
nsCOMPtr<nsIDOMNode> child;
offset = 0;
while (bHasMoreChildren)
{
inNode->GetLastChild(getter_AddRefs(child));
res = DeleteNode(child);
if (NS_FAILED(res)) return res;
res = InsertNode(child, *outNode, 0);
if (NS_FAILED(res)) return res;
inNode->HasChildNodes(&bHasMoreChildren);
}
res = DeleteNode(inNode);
return res;
}
///////////////////////////////////////////////////////////////////////////
// RemoveContainer: remove inNode, reparenting it's children into their
// the parent of inNode
//
nsresult
nsHTMLEditor::RemoveContainer(nsIDOMNode *inNode)
{
if (!inNode)
return NS_ERROR_NULL_POINTER;
if (nsHTMLEditUtils::IsBody(inNode))
return NS_ERROR_UNEXPECTED;
nsresult res;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
res = GetNodeLocation(inNode, &parent, &offset);
if (NS_FAILED(res)) return res;
// loop through the child nodes of inNode and promote them
// into inNode's parent.
PRBool bHasMoreChildren;
inNode->HasChildNodes(&bHasMoreChildren);
nsCOMPtr<nsIDOMNode> child;
while (bHasMoreChildren)
{
inNode->GetLastChild(getter_AddRefs(child));
res = DeleteNode(child);
if (NS_FAILED(res)) return res;
res = InsertNode(child, parent, offset);
if (NS_FAILED(res)) return res;
inNode->HasChildNodes(&bHasMoreChildren);
}
res = DeleteNode(inNode);
return res;
}
///////////////////////////////////////////////////////////////////////////
// InsertContainerAbove: insert a new parent for inNode, returned in outNode,
// which is contructed to be of type aNodeType. outNode becomes
// a child of inNode's earlier parent.
// Callers responsibility to make sure inNode's can be child
// of outNode, and outNode can be child of old parent.
nsresult
nsHTMLEditor::InsertContainerAbove(nsIDOMNode *inNode,
nsCOMPtr<nsIDOMNode> *outNode,
const nsString &aNodeType)
{
if (!inNode || !outNode)
return NS_ERROR_NULL_POINTER;
nsresult res;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
res = GetNodeLocation(inNode, &parent, &offset);
if (NS_FAILED(res)) return res;
// make new parent, outNode
res = CreateNode(aNodeType, parent, offset, getter_AddRefs(*outNode));
if (NS_FAILED(res)) return res;
// put inNode in new parent, outNode
res = DeleteNode(inNode);
if (NS_FAILED(res)) return res;
res = InsertNode(inNode, *outNode, 0);
if (NS_FAILED(res)) return res;
return NS_OK;
}

View File

@ -260,7 +260,7 @@ public:
/** All editor operations which alter the doc should be followed
* with a call to EndOperation, naming the action and direction */
NS_IMETHOD EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
NS_IMETHOD EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection, PRBool aSetSelection);
/** returns PR_TRUE if aParent can contain a child of type aTag */
PRBool CanContainTag(nsIDOMNode* aParent, const nsString &aTag);
@ -546,6 +546,23 @@ protected:
/* small utility routine to test the eEditorReadonly bit */
PRBool IsModifiable();
/* increase/decrease the font size of selection */
nsresult RelativeFontChange( PRInt32 aSizeChange);
/* helper routines for font size changing */
nsresult RelativeFontChangeOnTextNode( PRInt32 aSizeChange,
nsIDOMCharacterData *aTextNode,
PRInt32 aStartOffset,
PRInt32 aEndOffset);
nsresult RelativeFontChangeOnNode( PRInt32 aSizeChange,
nsIDOMNode *aNode);
/* helper routines for node/parent manipulations */
nsresult ReplaceContainer(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, const nsString &aNodeType);
nsresult RemoveContainer(nsIDOMNode *inNode);
nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, const nsString &aNodeType);
// Data members
protected:

View File

@ -150,7 +150,7 @@ nsTextEditRules::BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection)
NS_IMETHODIMP
nsTextEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
nsTextEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection, PRBool aSetSelection)
{
if (mLockRulesSniffing) return NS_OK;

View File

@ -52,7 +52,7 @@ public:
// nsEditRules methods
NS_IMETHOD Init(nsHTMLEditor *aEditor, PRUint32 aFlags);
NS_IMETHOD BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection);
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection);
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection, PRBool aSetSelection);
NS_IMETHOD WillDoAction(nsIDOMSelection *aSelection, nsRulesInfo *aInfo, PRBool *aCancel, PRBool *aHandled);
NS_IMETHOD DidDoAction(nsIDOMSelection *aSelection, nsRulesInfo *aInfo, nsresult aResult);
NS_IMETHOD GetFlags(PRUint32 *aFlags);