refactoring text insertion code; indent/outdent now work with lists and list items.

git-svn-id: svn://10.0.0.236/trunk@44276 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
jfrancis%netscape.com 1999-08-24 08:56:51 +00:00
parent 0d61526430
commit 99de773e68
10 changed files with 902 additions and 506 deletions

View File

@ -146,14 +146,16 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection,
TypeInState typeInState,
PRInt32 aMaxLength)
{ if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
// initialize out param
*aCancel = PR_FALSE;
*aCancel = PR_TRUE;
nsresult res;
char specialChars[] = {'\t',' ',nbsp,'\n',0};
mEditor->BeginTransaction(); // we have to batch this in case there are returns
// Insert Break txns don't auto merge with insert text txns
// we have to batch this in case there are returns
// Insert Break txns don't auto merge with insert text txns
nsAutoEditBatch beginBatching(mEditor);
// strategy: there are simple cases and harder cases. The harder cases
// we handle recursively by breaking them into a series of simple cases.
@ -165,54 +167,52 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection,
// 5) a run of chars containing no spaces, nbsp's, tabs, or returns
char nbspStr[2] = {nbsp, 0};
// is it a solo tab?
if (*inString == "\t" )
{
res = InsertTab(aSelection,aCancel,aTxn,outString);
}
// is it a solo space?
else if (*inString == " ")
{
res = InsertSpace(aSelection,aCancel,aTxn,outString);
}
// is it a solo nbsp?
else if (*inString == nbspStr)
{
res = InsertSpace(aSelection,aCancel,aTxn,outString);
}
// is it a solo return?
else if (*inString == "\n")
{
// special case - cancel default handling
*aCancel = PR_TRUE;
res = mEditor->InsertBreak();
}
else
{
// is it an innocous run of chars? no spaces, nbsps, returns, tabs?
PRInt32 pos = inString->FindCharInSet(specialChars);
if (pos == -1)
nsString theString(*inString); // copy instr for now
PRInt32 pos = theString.FindCharInSet(specialChars);
while (theString.Length())
{
// no special chars, easy case
res = nsTextEditRules::WillInsertText(aSelection, aCancel, aTxn, inString, outString, typeInState, aMaxLength);
}
else
{
// else we need to break it up into two parts and recurse
*aCancel = PR_TRUE;
nsString firstString;
nsString restOfString(*inString);
PRBool bCancel;
nsString partialString;
// if first char is special, then use just it
if (pos == 0) pos = 1;
inString->Left(firstString, pos);
restOfString.Cut(0, pos);
if (NS_SUCCEEDED(mEditor->InsertText(firstString)))
{
res = mEditor->InsertText(restOfString);
}
if (pos == -1) pos = theString.Length();
theString.Left(partialString, pos);
theString.Cut(0, pos);
// is it a solo tab?
if (partialString == "\t" )
{
res = InsertTab(aSelection,&bCancel,aTxn,outString);
if (NS_FAILED(res)) return res;
res = DoTextInsertion(aSelection, aCancel, aTxn, outString, typeInState);
}
// is it a solo space?
else if (partialString == " ")
{
res = InsertSpace(aSelection,&bCancel,aTxn,outString);
if (NS_FAILED(res)) return res;
res = DoTextInsertion(aSelection, aCancel, aTxn, outString, typeInState);
}
// is it a solo nbsp?
else if (partialString == nbspStr)
{
res = InsertSpace(aSelection,&bCancel,aTxn,outString);
if (NS_FAILED(res)) return res;
res = DoTextInsertion(aSelection, aCancel, aTxn, outString, typeInState);
}
// is it a solo return?
else if (partialString == "\n")
{
res = mEditor->InsertBreak();
}
else
{
res = DoTextInsertion(aSelection, aCancel, aTxn, &partialString, typeInState);
}
if (NS_FAILED(res)) return res;
pos = theString.FindCharInSet(specialChars);
}
}
mEditor->EndTransaction();
return res;
}
@ -224,6 +224,8 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel)
*aCancel = PR_FALSE;
nsresult res;
res = WillInsert(aSelection, aCancel);
if (NS_FAILED(res)) return res;
// if the selection isn't collapsed, delete it.
PRBool bCollapsed;
@ -235,7 +237,7 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel)
if (NS_FAILED(res)) return res;
}
//smart splitting rules
// smart splitting rules
nsCOMPtr<nsIDOMNode> node;
PRInt32 offset;
PRBool isPRE;
@ -251,7 +253,7 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel)
{
nsString theString = "\n";
*aCancel = PR_TRUE;
return mEditor->InsertText(theString);
return mEditor->InsertTextImpl(theString);
}
nsCOMPtr<nsIDOMNode> blockParent;
@ -263,7 +265,7 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel)
if (!blockParent) return NS_ERROR_FAILURE;
// headers: put selection after the header
// headers: close (or split) header
if (IsHeader(blockParent))
{
res = ReturnInHeader(aSelection, blockParent, node, offset);
@ -286,8 +288,7 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel)
return NS_OK;
}
return WillInsert(aSelection, aCancel);
return res;
}
@ -426,10 +427,9 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection, nsIEditor::ESe
return NS_OK;
}
// else do default
return NS_OK;
}
// else do default
return NS_OK;
}
// else we have a non collapsed selection
@ -829,21 +829,16 @@ nsHTMLEditRules::WillIndent(nsIDOMSelection *aSelection, PRBool *aCancel)
if (NS_FAILED(res)) return res;
// some logic for putting list items into nested lists...
if (IsListItem(curNode))
if (IsList(curParent))
{
if (!curList || transitionList[i])
{
nsAutoString quoteType("ol"); // XXX - get correct list type
if (mEditor->CanContainTag(curParent,quoteType))
{
res = mEditor->CreateNode(quoteType, curParent, offset, getter_AddRefs(curList));
if (NS_FAILED(res)) return res;
// curQuote is now the correct thing to put curNode in
}
else
{
printf("trying to put a list in a bad place\n");
}
nsAutoString listTag;
nsEditor::GetTagString(curParent,listTag);
// create a new nested list of correct type
res = mEditor->CreateNode(listTag, curParent, offset, getter_AddRefs(curList));
if (NS_FAILED(res)) return res;
// curList is now the correct thing to put curNode in
}
// tuck the node into the end of the active list
PRUint32 listLen;
@ -935,7 +930,78 @@ nsHTMLEditRules::WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel)
res = nsEditor::GetNodeLocation(curNode, &curParent, &offset);
if (NS_FAILED(res)) return res;
if (transitionList[i])
if (IsList(curParent)) // move node out of list
{
if (IsList(curNode)) // just unwrap this sublist
{
res = RemoveContainer(curNode);
if (NS_FAILED(res)) return res;
}
else // we are moving a list item, but not whole list
{
// if it's first or last list item, dont need to split the list
// otherwise we do.
nsCOMPtr<nsIDOMNode> curParPar;
PRInt32 parOffset;
res = nsEditor::GetNodeLocation(curParent, &curParPar, &parOffset);
if (NS_FAILED(res)) return res;
PRBool bIsFirstListItem;
res = IsFirstEditableChild(curNode, &bIsFirstListItem);
if (NS_FAILED(res)) return res;
PRBool bIsLastListItem;
res = IsLastEditableChild(curNode, &bIsLastListItem);
if (NS_FAILED(res)) return res;
if (!bIsFirstListItem && !bIsLastListItem)
{
// split the list
nsCOMPtr<nsIDOMNode> newBlock;
res = mEditor->SplitNode(curParent, offset, getter_AddRefs(newBlock));
if (NS_FAILED(res)) return res;
}
if (!bIsFirstListItem) parOffset++;
res = mEditor->DeleteNode(curNode);
if (NS_FAILED(res)) return res;
res = mEditor->InsertNode(curNode, curParPar, parOffset);
if (NS_FAILED(res)) return res;
// convert list items to divs if we promoted them out of list
if (!IsList(curParPar) && IsListItem(curNode))
{
nsAutoString blockType("div");
nsCOMPtr<nsIDOMNode> newBlock;
res = ReplaceContainer(curNode,&newBlock,blockType);
if (NS_FAILED(res)) return res;
}
}
}
else if (IsList(curNode)) // node is a list, but parent is non-list: move list items out
{
nsCOMPtr<nsIDOMNode> child;
curNode->GetLastChild(getter_AddRefs(child));
while (child)
{
res = mEditor->DeleteNode(child);
if (NS_FAILED(res)) return res;
res = mEditor->InsertNode(child, curParent, offset);
if (NS_FAILED(res)) return res;
if (IsListItem(child))
{
nsAutoString blockType("div");
nsCOMPtr<nsIDOMNode> newBlock;
res = ReplaceContainer(child,&newBlock,blockType);
if (NS_FAILED(res)) return res;
}
curNode->GetLastChild(getter_AddRefs(child));
}
}
else if (transitionList[i]) // not list related - look for enclosing blockquotes and remove
{
// look for a blockquote somewhere above us and remove it.
// this is a hack until i think about outdent for real.
@ -2391,4 +2457,65 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString
}
nsresult
nsHTMLEditRules::IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst)
{
// check parms
if (!aOutIsFirst || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutIsFirst = PR_FALSE;
// find first editable child and compare it to aNode
nsCOMPtr<nsIDOMNode> parent;
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
if (!parent) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> child;
parent->GetFirstChild(getter_AddRefs(child));
if (!child) return NS_ERROR_FAILURE;
if (!mEditor->IsEditable(child))
{
nsCOMPtr<nsIDOMNode> tmp;
res = mEditor->GetNextNode(child, PR_TRUE, getter_AddRefs(tmp));
if (NS_FAILED(res)) return res;
if (!tmp) return NS_ERROR_FAILURE;
child = tmp;
}
*aOutIsFirst = (child == aNode);
return res;
}
nsresult
nsHTMLEditRules::IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast)
{
// check parms
if (!aOutIsLast || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutIsLast = PR_FALSE;
// find last editable child and compare it to aNode
nsCOMPtr<nsIDOMNode> parent;
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
if (!parent) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> child;
parent->GetLastChild(getter_AddRefs(child));
if (!child) return NS_ERROR_FAILURE;
if (!mEditor->IsEditable(child))
{
nsCOMPtr<nsIDOMNode> tmp;
res = mEditor->GetPriorNode(child, PR_TRUE, getter_AddRefs(tmp));
if (NS_FAILED(res)) return res;
if (!tmp) return NS_ERROR_FAILURE;
child = tmp;
}
*aOutIsLast = (child == aNode);
return res;
}

View File

@ -108,6 +108,9 @@ protected:
nsresult RemoveContainer(nsIDOMNode *inNode);
nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, nsString &aNodeType);
nsresult IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst);
nsresult IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast);
};
#endif //nsHTMLEditRules_h__

View File

@ -3507,18 +3507,19 @@ nsresult nsHTMLEditor::GetTextSelectionOffsets(nsIDOMSelection *aSelection,
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
range->GetCommonParent(getter_AddRefs(parentNode));
}
else {
parentNode = do_QueryInterface(startNode);
}
else
{
parentNode = do_QueryInterface(startNode);
}
nsCOMPtr<nsIContentIterator> iter;
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
nsIContentIterator::GetIID(),
getter_AddRefs(iter));
if (NS_FAILED(result)) return result;
if (!iter) return NS_ERROR_NULL_POINTER;
if (NS_FAILED(result)) return result;
if (!iter) return NS_ERROR_NULL_POINTER;
PRUint32 totalLength=0;
nsCOMPtr<nsIDOMCharacterData>textNode;
nsCOMPtr<nsIContent>blockParentContent = do_QueryInterface(parentNode);

View File

@ -75,8 +75,8 @@ nsTextEditRules::Init(nsHTMLEditor *aEditor, PRUint32 aFlags)
nsCOMPtr<nsIDOMSelection> selection;
mEditor->GetSelection(getter_AddRefs(selection));
NS_ASSERTION(selection, "editor cannot get selection");
nsresult result = CreateBogusNodeIfNeeded(selection); // this method handles null selection, which should never happen anyway
return result;
nsresult res = CreateBogusNodeIfNeeded(selection); // this method handles null selection, which should never happen anyway
return res;
}
NS_IMETHODIMP
@ -263,93 +263,32 @@ nsTextEditRules::WillInsertText(nsIDOMSelection *aSelection,
if (!aSelection || !aCancel || !aInString || !aOutString) {return NS_ERROR_NULL_POINTER;}
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
nsresult result;
nsString inString = *aInString; // we might want to mutate the input
// before setting the output, do that in a local var
if ((-1 != aMaxLength) && (mFlags & nsIHTMLEditor::eEditorPlaintextMask))
{
// Get the current text length.
// Get the length of inString.
// Get the length of the selection.
// If selection is collapsed, it is length 0.
// Subtract the length of the selection from the len(doc)
// since we'll delete the selection on insert.
// This is resultingDocLength.
// If (resultingDocLength) is at or over max, cancel the insert
// If (resultingDocLength) + (length of input) > max,
// set aOutString to subset of inString so length = max
PRInt32 docLength;
result = mEditor->GetDocumentLength(&docLength);
if (NS_FAILED(result)) { return result; }
PRInt32 start, end;
result = mEditor->GetTextSelectionOffsets(aSelection, start, end);
if (NS_FAILED(result)) { return result; }
PRInt32 selectionLength = end-start;
if (selectionLength<0) { selectionLength *= (-1); }
PRInt32 resultingDocLength = docLength - selectionLength;
if (resultingDocLength >= aMaxLength)
{
*aOutString = "";
*aCancel = PR_TRUE;
return result;
}
else
{
PRInt32 inCount = inString.Length();
if ((inCount+resultingDocLength) > aMaxLength)
{
inString.Truncate(aMaxLength-resultingDocLength);
}
}
}
nsresult res;
// initialize out params
*aCancel = PR_FALSE;
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
{
// manage the password buffer
PRInt32 start, end;
result = mEditor->GetTextSelectionOffsets(aSelection, start, end);
NS_ASSERTION((NS_SUCCEEDED(result)), "getTextSelectionOffsets failed!");
mPasswordText.Insert(inString, start);
char *password = mPasswordText.ToNewCString();
printf("mPasswordText is %s\n", password);
delete [] password;
// change the output to '*' only
PRInt32 length = inString.Length();
PRInt32 i;
for (i=0; i<length; i++)
*aOutString += '*';
}
else
{
*aOutString = inString;
}
*aCancel = PR_TRUE;
*aOutString = *aInString;
if (mBogusNode || (PR_TRUE==aTypeInState.IsAnySet()))
// handle docs with a max length
res = TruncateInsertionIfNeeded(aSelection, aInString, aOutString, aMaxLength);
if (NS_FAILED(res)) return res;
if (aOutString->Length())
{
result = TransactionFactory::GetNewTransaction(PlaceholderTxn::GetCID(), (EditTxn **)aTxn);
if (NS_FAILED(result)) { return result; }
if (!*aTxn) { return NS_ERROR_NULL_POINTER; }
(*aTxn)->SetName(InsertTextTxn::gInsertTextTxnName);
mEditor->Do(*aTxn);
}
result = WillInsert(aSelection, aCancel);
if (NS_SUCCEEDED(result) && (PR_FALSE==*aCancel))
{
if (PR_TRUE==aTypeInState.IsAnySet())
{ // for every property that is set, insert a new inline style node
result = CreateStyleForInsertText(aSelection, aTypeInState);
// handle password field docs
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
{
res = EchoInsertionToPWBuff(aSelection, aOutString);
if (NS_FAILED(res)) return res;
}
// do text insertion
PRBool bCancel;
res = DoTextInsertion(aSelection, &bCancel, aTxn, aOutString, aTypeInState);
if (NS_FAILED(res)) return res;
}
return result;
return res;
}
nsresult
@ -371,8 +310,8 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
// Otherwise, create the text node and the new inline style parents.
nsCOMPtr<nsIDOMNode>anchor;
PRInt32 offset;
nsresult result = aSelection->GetAnchorNode( getter_AddRefs(anchor));
if (NS_SUCCEEDED(result) && NS_SUCCEEDED(aSelection->GetAnchorOffset(&offset)) && anchor)
nsresult res = aSelection->GetAnchorNode( getter_AddRefs(anchor));
if (NS_SUCCEEDED(res) && NS_SUCCEEDED(aSelection->GetAnchorOffset(&offset)) && anchor)
{
nsCOMPtr<nsIDOMCharacterData>anchorAsText;
anchorAsText = do_QueryInterface(anchor);
@ -382,7 +321,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
// create an empty text node by splitting the selected text node according to offset
if (0==offset)
{
result = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
res = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
}
else
{
@ -391,7 +330,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
if (length==(PRUint32)offset)
{
// newTextNode will be the left node
result = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
res = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
// but we want the right node in this case
newTextNode = do_QueryInterface(anchor);
}
@ -399,21 +338,21 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
{
// splitting anchor twice sets newTextNode as an empty text node between
// two halves of the original text node
result = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
if (NS_SUCCEEDED(result)) {
result = mEditor->SplitNode(anchorAsText, 0, getter_AddRefs(newTextNode));
res = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
if (NS_SUCCEEDED(res)) {
res = mEditor->SplitNode(anchorAsText, 0, getter_AddRefs(newTextNode));
}
}
}
// now we have the new text node we are going to insert into.
// create style nodes or move it up the content hierarchy as needed.
if ((NS_SUCCEEDED(result)) && newTextNode)
if ((NS_SUCCEEDED(res)) && newTextNode)
{
nsCOMPtr<nsIDOMNode>newStyleNode;
if (aTypeInState.IsSet(NS_TYPEINSTATE_BOLD))
{
if (PR_TRUE==aTypeInState.GetBold()) {
result = InsertStyleNode(newTextNode, nsIEditProperty::b, aSelection, getter_AddRefs(newStyleNode));
res = InsertStyleNode(newTextNode, nsIEditProperty::b, aSelection, getter_AddRefs(newStyleNode));
}
else {
printf("not yet implemented, make not bold in a bold context\n");
@ -422,7 +361,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
if (aTypeInState.IsSet(NS_TYPEINSTATE_ITALIC))
{
if (PR_TRUE==aTypeInState.GetItalic()) {
result = InsertStyleNode(newTextNode, nsIEditProperty::i, aSelection, getter_AddRefs(newStyleNode));
res = InsertStyleNode(newTextNode, nsIEditProperty::i, aSelection, getter_AddRefs(newStyleNode));
}
else
{
@ -432,7 +371,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
if (aTypeInState.IsSet(NS_TYPEINSTATE_UNDERLINE))
{
if (PR_TRUE==aTypeInState.GetUnderline()) {
result = InsertStyleNode(newTextNode, nsIEditProperty::u, aSelection, getter_AddRefs(newStyleNode));
res = InsertStyleNode(newTextNode, nsIEditProperty::u, aSelection, getter_AddRefs(newStyleNode));
}
else
{
@ -445,7 +384,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
aTypeInState.GetFontColor(value);
nsAutoString attr;
nsIEditProperty::color->ToString(attr);
result = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
res = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
}
if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTFACE))
{
@ -453,7 +392,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
aTypeInState.GetFontFace(value);
nsAutoString attr;
nsIEditProperty::face->ToString(attr);
result = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
res = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
}
if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTSIZE))
{
@ -461,7 +400,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
aTypeInState.GetFontSize(value);
nsAutoString attr;
nsIEditProperty::size->ToString(attr);
result = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
res = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
}
}
}
@ -500,7 +439,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
}
}
}
return result;
return res;
}
nsresult
@ -509,23 +448,23 @@ nsTextEditRules::CreateFontStyleForInsertText(nsIDOMNode *aNewTextNode,
const nsString &aValue,
nsIDOMSelection *aSelection)
{
nsresult result = NS_OK;
nsresult res = NS_OK;
nsCOMPtr<nsIDOMNode>newStyleNode;
if (0!=aValue.Length())
{
result = InsertStyleNode(aNewTextNode, nsIEditProperty::font, aSelection, getter_AddRefs(newStyleNode));
if (NS_FAILED(result)) return result;
res = InsertStyleNode(aNewTextNode, nsIEditProperty::font, aSelection, getter_AddRefs(newStyleNode));
if (NS_FAILED(res)) return res;
if (!newStyleNode) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMElement>element = do_QueryInterface(newStyleNode);
if (element) {
result = mEditor->SetAttribute(element, aAttr, aValue);
res = mEditor->SetAttribute(element, aAttr, aValue);
}
}
else
{
printf("not yet implemented, undo font in an font context\n");
}
return result;
return res;
}
nsresult
@ -537,33 +476,33 @@ nsTextEditRules::InsertStyleNode(nsIDOMNode *aNode,
NS_ASSERTION(aNode && aTag, "bad args");
if (!aNode || !aTag) { return NS_ERROR_NULL_POINTER; }
nsresult result;
nsresult res;
nsCOMPtr<nsIDOMNode>parent;
aNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(result)) return result;
if (NS_FAILED(res)) return res;
if (!parent) return NS_ERROR_NULL_POINTER;
PRInt32 offsetInParent;
result = nsEditor::GetChildOffset(aNode, parent, offsetInParent);
if (NS_FAILED(result)) return result;
res = nsEditor::GetChildOffset(aNode, parent, offsetInParent);
if (NS_FAILED(res)) return res;
nsAutoString tag;
aTag->ToString(tag);
result = mEditor->CreateNode(tag, parent, offsetInParent, aNewNode);
if (NS_FAILED(result)) return result;
res = mEditor->CreateNode(tag, parent, offsetInParent, aNewNode);
if (NS_FAILED(res)) return res;
if (!aNewNode) return NS_ERROR_NULL_POINTER;
result = mEditor->DeleteNode(aNode);
if (NS_SUCCEEDED(result))
res = mEditor->DeleteNode(aNode);
if (NS_SUCCEEDED(res))
{
result = mEditor->InsertNode(aNode, *aNewNode, 0);
if (NS_SUCCEEDED(result)) {
res = mEditor->InsertNode(aNode, *aNewNode, 0);
if (NS_SUCCEEDED(res)) {
if (aSelection) {
result = aSelection->Collapse(aNode, 0);
res = aSelection->Collapse(aNode, 0);
}
}
}
return result;
return res;
}
@ -573,24 +512,24 @@ nsTextEditRules::InsertStyleAndNewTextNode(nsIDOMNode *aParentNode, nsIAtom *aTa
NS_ASSERTION(aParentNode && aTag, "bad args");
if (!aParentNode || !aTag) { return NS_ERROR_NULL_POINTER; }
nsresult result;
nsresult res;
// if the selection already points to a text node, just call InsertStyleNode()
if (aSelection)
{
nsCOMPtr<nsIDOMNode>anchor;
PRInt32 offset;
result = aSelection->GetAnchorNode(getter_AddRefs(anchor));
if (NS_FAILED(result)) return result;
res = aSelection->GetAnchorNode(getter_AddRefs(anchor));
if (NS_FAILED(res)) return res;
if (!anchor) return NS_ERROR_NULL_POINTER;
result = aSelection->GetAnchorOffset(&offset);
if (NS_FAILED(result)) return result;
res = aSelection->GetAnchorOffset(&offset);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMCharacterData>anchorAsText;
anchorAsText = do_QueryInterface(anchor);
if (anchorAsText)
{
nsCOMPtr<nsIDOMNode> newStyleNode;
result = InsertStyleNode(anchor, aTag, aSelection, getter_AddRefs(newStyleNode));
return result;
res = InsertStyleNode(anchor, aTag, aSelection, getter_AddRefs(newStyleNode));
return res;
}
}
// if we get here, there is no selected text node so we create one.
@ -598,30 +537,30 @@ nsTextEditRules::InsertStyleAndNewTextNode(nsIDOMNode *aParentNode, nsIAtom *aTa
aTag->ToString(tag);
nsCOMPtr<nsIDOMNode>newStyleNode;
nsCOMPtr<nsIDOMNode>newTextNode;
result = mEditor->CreateNode(tag, aParentNode, 0, getter_AddRefs(newStyleNode));
if (NS_FAILED(result)) return result;
res = mEditor->CreateNode(tag, aParentNode, 0, getter_AddRefs(newStyleNode));
if (NS_FAILED(res)) return res;
if (!newStyleNode) return NS_ERROR_NULL_POINTER;
result = mEditor->CreateNode(nsEditor::GetTextNodeTag(), newStyleNode, 0, getter_AddRefs(newTextNode));
if (NS_FAILED(result)) return result;
res = mEditor->CreateNode(nsEditor::GetTextNodeTag(), newStyleNode, 0, getter_AddRefs(newTextNode));
if (NS_FAILED(res)) return res;
if (!newTextNode) return NS_ERROR_NULL_POINTER;
if (aSelection) {
result = aSelection->Collapse(newTextNode, 0);
res = aSelection->Collapse(newTextNode, 0);
}
return result;
return res;
}
nsresult
nsTextEditRules::WillSetTextProperty(nsIDOMSelection *aSelection, PRBool *aCancel)
{
nsresult result = NS_OK;
nsresult res = NS_OK;
// XXX: should probably return a success value other than NS_OK that means "not allowed"
if (nsIHTMLEditor::eEditorPlaintextMask & mFlags) {
*aCancel = PR_TRUE;
}
return result;
return res;
}
nsresult
@ -633,13 +572,13 @@ nsTextEditRules::DidSetTextProperty(nsIDOMSelection *aSelection, nsresult aResul
nsresult
nsTextEditRules::WillRemoveTextProperty(nsIDOMSelection *aSelection, PRBool *aCancel)
{
nsresult result = NS_OK;
nsresult res = NS_OK;
// XXX: should probably return a success value other than NS_OK that means "not allowed"
if (nsIHTMLEditor::eEditorPlaintextMask & mFlags) {
*aCancel = PR_TRUE;
}
return result;
return res;
}
nsresult
@ -697,37 +636,37 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection,
nsIEditor::ESelectionCollapseDirection aCollapsedAction,
nsresult aResult)
{
nsresult result = aResult; // if aResult is an error, we just return it
nsresult res = aResult; // if aResult is an error, we just return it
if (!aSelection) { return NS_ERROR_NULL_POINTER; }
PRBool isCollapsed;
aSelection->GetIsCollapsed(&isCollapsed);
NS_ASSERTION(PR_TRUE==isCollapsed, "selection not collapsed after delete selection.");
// if the delete selection resulted in no content
// insert a special bogus text node with a &nbsp; character in it.
if (NS_SUCCEEDED(result)) // only do this work if DeleteSelection completed successfully
if (NS_SUCCEEDED(res)) // only do this work if DeleteSelection completed successfully
{
result = CreateBogusNodeIfNeeded(aSelection);
res = CreateBogusNodeIfNeeded(aSelection);
// if we don't have an empty document, check the selection to see if any collapsing is necessary
if (!mBogusNode)
{
nsCOMPtr<nsIDOMNode>anchor;
PRInt32 offset;
result = aSelection->GetAnchorNode(getter_AddRefs(anchor));
if (NS_FAILED(result)) return result;
res = aSelection->GetAnchorNode(getter_AddRefs(anchor));
if (NS_FAILED(res)) return res;
if (!anchor) return NS_ERROR_NULL_POINTER;
result = aSelection->GetAnchorOffset(&offset);
if (NS_FAILED(result)) return result;
res = aSelection->GetAnchorOffset(&offset);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMNodeList> anchorChildren;
result = anchor->GetChildNodes(getter_AddRefs(anchorChildren));
res = anchor->GetChildNodes(getter_AddRefs(anchorChildren));
nsCOMPtr<nsIDOMNode> selectedNode;
if ((NS_SUCCEEDED(result)) && anchorChildren) {
result = anchorChildren->Item(offset, getter_AddRefs(selectedNode));
if ((NS_SUCCEEDED(res)) && anchorChildren) {
res = anchorChildren->Item(offset, getter_AddRefs(selectedNode));
}
else {
selectedNode = do_QueryInterface(anchor);
}
if ((NS_SUCCEEDED(result)) && selectedNode)
if ((NS_SUCCEEDED(res)) && selectedNode)
{
nsCOMPtr<nsIDOMCharacterData>selectedNodeAsText;
selectedNodeAsText = do_QueryInterface(selectedNode);
@ -744,10 +683,10 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection,
PRUint32 siblingLength; // the length of siblingNode before the join
siblingNodeAsText->GetLength(&siblingLength);
nsCOMPtr<nsIDOMNode> parentNode;
result = selectedNode->GetParentNode(getter_AddRefs(parentNode));
if (NS_FAILED(result)) return result;
res = selectedNode->GetParentNode(getter_AddRefs(parentNode));
if (NS_FAILED(res)) return res;
if (!parentNode) return NS_ERROR_NULL_POINTER;
result = mEditor->JoinNodes(siblingNode, selectedNode, parentNode);
res = mEditor->JoinNodes(siblingNode, selectedNode, parentNode);
// selectedNode will remain after the join, siblingNode is removed
}
}
@ -761,22 +700,22 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection,
PRUint32 selectedNodeLength; // the length of siblingNode before the join
selectedNodeAsText->GetLength(&selectedNodeLength);
nsCOMPtr<nsIDOMNode> parentNode;
result = selectedNode->GetParentNode(getter_AddRefs(parentNode));
if (NS_FAILED(result)) return result;
res = selectedNode->GetParentNode(getter_AddRefs(parentNode));
if (NS_FAILED(res)) return res;
if (!parentNode) return NS_ERROR_NULL_POINTER;
result = mEditor->JoinNodes(selectedNode, siblingNode, parentNode);
if (NS_FAILED(result)) return result;
res = mEditor->JoinNodes(selectedNode, siblingNode, parentNode);
if (NS_FAILED(res)) return res;
// selectedNode will remain after the join, siblingNode is removed
// set selection
result = aSelection->Collapse(siblingNode, selectedNodeLength);
res = aSelection->Collapse(siblingNode, selectedNodeLength);
}
}
}
}
}
}
return result;
return res;
}
nsresult
@ -789,7 +728,7 @@ nsTextEditRules::WillUndo(nsIDOMSelection *aSelection, PRBool *aCancel)
return NS_OK;
}
/* the idea here is to see if the magic empty node has suddenly reappeared as the result of the undo.
/* the idea here is to see if the magic empty node has suddenly reappeared as the res of the undo.
* if it has, set our state so we remember it.
* There is a tradeoff between doing here and at redo, or doing it everywhere else that might care.
* Since undo and redo are relatively rare, it makes sense to take the (small) performance hit here.
@ -797,9 +736,9 @@ nsTextEditRules::WillUndo(nsIDOMSelection *aSelection, PRBool *aCancel)
nsresult
nsTextEditRules:: DidUndo(nsIDOMSelection *aSelection, nsresult aResult)
{
nsresult result = aResult; // if aResult is an error, we return it.
nsresult res = aResult; // if aResult is an error, we return it.
if (!aSelection) { return NS_ERROR_NULL_POINTER; }
if (NS_SUCCEEDED(result))
if (NS_SUCCEEDED(res))
{
if (mBogusNode) {
mBogusNode = do_QueryInterface(nsnull);
@ -808,11 +747,11 @@ nsTextEditRules:: DidUndo(nsIDOMSelection *aSelection, nsresult aResult)
{
nsCOMPtr<nsIDOMNode>node;
PRInt32 offset;
result = aSelection->GetAnchorNode(getter_AddRefs(node));
if (NS_FAILED(result)) return result;
res = aSelection->GetAnchorNode(getter_AddRefs(node));
if (NS_FAILED(res)) return res;
if (!node) return NS_ERROR_NULL_POINTER;
result = aSelection->GetAnchorOffset(&offset);
if (NS_FAILED(result)) return result;
res = aSelection->GetAnchorOffset(&offset);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(node);
if (element)
@ -825,11 +764,11 @@ nsTextEditRules:: DidUndo(nsIDOMSelection *aSelection, nsresult aResult)
}
}
nsCOMPtr<nsIDOMNode> temp;
result = node->GetParentNode(getter_AddRefs(temp));
res = node->GetParentNode(getter_AddRefs(temp));
node = do_QueryInterface(temp);
}
}
return result;
return res;
}
nsresult
@ -845,9 +784,9 @@ nsTextEditRules::WillRedo(nsIDOMSelection *aSelection, PRBool *aCancel)
nsresult
nsTextEditRules::DidRedo(nsIDOMSelection *aSelection, nsresult aResult)
{
nsresult result = aResult; // if aResult is an error, we return it.
nsresult res = aResult; // if aResult is an error, we return it.
if (!aSelection) { return NS_ERROR_NULL_POINTER; }
if (NS_SUCCEEDED(result))
if (NS_SUCCEEDED(res))
{
if (mBogusNode) {
mBogusNode = do_QueryInterface(nsnull);
@ -856,11 +795,11 @@ nsTextEditRules::DidRedo(nsIDOMSelection *aSelection, nsresult aResult)
{
nsCOMPtr<nsIDOMNode>node;
PRInt32 offset;
result = aSelection->GetAnchorNode(getter_AddRefs(node));
if (NS_FAILED(result)) return result;
res = aSelection->GetAnchorNode(getter_AddRefs(node));
if (NS_FAILED(res)) return res;
if (!node) return NS_ERROR_NULL_POINTER;
result = aSelection->GetAnchorOffset(&offset);
if (NS_FAILED(result)) return result;
res = aSelection->GetAnchorOffset(&offset);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(node);
if (element)
@ -873,11 +812,11 @@ nsTextEditRules::DidRedo(nsIDOMSelection *aSelection, nsresult aResult)
}
}
nsCOMPtr<nsIDOMNode> temp;
result = node->GetParentNode(getter_AddRefs(temp));
res = node->GetParentNode(getter_AddRefs(temp));
node = do_QueryInterface(temp);
}
}
return result;
return res;
}
nsresult
@ -913,8 +852,8 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection)
if (!mEditor) { return NS_ERROR_NULL_POINTER; }
nsCOMPtr<nsIDOMElement> bodyElement;
nsresult result = mEditor->GetBodyElement(getter_AddRefs(bodyElement));
if (NS_FAILED(result)) return result;
nsresult res = mEditor->GetBodyElement(getter_AddRefs(bodyElement));
if (NS_FAILED(res)) return res;
if (!bodyElement) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode>bodyNode = do_QueryInterface(bodyElement);
@ -923,8 +862,8 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection)
// if no editable content is found, insert the bogus node
PRBool needsBogusContent=PR_TRUE;
nsCOMPtr<nsIDOMNode>bodyChild;
result = bodyNode->GetFirstChild(getter_AddRefs(bodyChild));
while ((NS_SUCCEEDED(result)) && bodyChild)
res = bodyNode->GetFirstChild(getter_AddRefs(bodyChild));
while ((NS_SUCCEEDED(res)) && bodyChild)
{
if (PR_TRUE==mEditor->IsEditable(bodyChild))
{
@ -938,15 +877,15 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection)
if (PR_TRUE==needsBogusContent)
{
// set mBogusNode to be the newly created <P>
result = mEditor->CreateNode(nsAutoString("P"), bodyNode, 0,
res = mEditor->CreateNode(nsAutoString("P"), bodyNode, 0,
getter_AddRefs(mBogusNode));
if (NS_FAILED(result)) return result;
if (NS_FAILED(res)) return res;
if (!mBogusNode) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode>newTNode;
result = mEditor->CreateNode(nsEditor::GetTextNodeTag(), mBogusNode, 0,
res = mEditor->CreateNode(nsEditor::GetTextNodeTag(), mBogusNode, 0,
getter_AddRefs(newTNode));
if (NS_FAILED(result)) return result;
if (NS_FAILED(res)) return res;
if (!newTNode) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMCharacterData>newNodeAsText;
@ -968,6 +907,119 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection)
newPElement->SetAttribute(att, val);
}
}
return result;
return res;
}
nsresult
nsTextEditRules::TruncateInsertionIfNeeded(nsIDOMSelection *aSelection,
const nsString *aInString,
nsString *aOutString,
PRInt32 aMaxLength)
{
if (!aSelection || !aInString || !aOutString) {return NS_ERROR_NULL_POINTER;}
nsresult res = NS_OK;
*aOutString = *aInString;
if ((-1 != aMaxLength) && (mFlags & nsIHTMLEditor::eEditorPlaintextMask))
{
// Get the current text length.
// Get the length of inString.
// Get the length of the selection.
// If selection is collapsed, it is length 0.
// Subtract the length of the selection from the len(doc)
// since we'll delete the selection on insert.
// This is resultingDocLength.
// If (resultingDocLength) is at or over max, cancel the insert
// If (resultingDocLength) + (length of input) > max,
// set aOutString to subset of inString so length = max
PRInt32 docLength;
res = mEditor->GetDocumentLength(&docLength);
if (NS_FAILED(res)) { return res; }
PRInt32 start, end;
res = mEditor->GetTextSelectionOffsets(aSelection, start, end);
if (NS_FAILED(res)) { return res; }
PRInt32 selectionLength = end-start;
if (selectionLength<0) { selectionLength *= (-1); }
PRInt32 resultingDocLength = docLength - selectionLength;
if (resultingDocLength >= aMaxLength)
{
*aOutString = "";
return res;
}
else
{
PRInt32 inCount = aOutString->Length();
if ((inCount+resultingDocLength) > aMaxLength)
{
aOutString->Truncate(aMaxLength-resultingDocLength);
}
}
}
return res;
}
nsresult
nsTextEditRules::EchoInsertionToPWBuff(nsIDOMSelection *aSelection, nsString *aOutString)
{
if (!aSelection || !aOutString) {return NS_ERROR_NULL_POINTER;}
// manage the password buffer
PRInt32 start, end;
nsresult res = mEditor->GetTextSelectionOffsets(aSelection, start, end);
NS_ASSERTION((NS_SUCCEEDED(res)), "getTextSelectionOffsets failed!");
mPasswordText.Insert(*aOutString, start);
#ifdef NS_DEBUG
char *password = mPasswordText.ToNewCString();
printf("mPasswordText is %s\n", password);
delete [] password;
#endif
// change the output to '*' only
PRInt32 length = aOutString->Length();
PRInt32 i;
for (i=0; i<length; i++)
*aOutString += '*';
return res;
}
nsresult
nsTextEditRules::DoTextInsertion(nsIDOMSelection *aSelection,
PRBool *aCancel,
PlaceholderTxn **aTxn,
const nsString *aInString,
TypeInState aTypeInState)
{
if (!aSelection || !aCancel || !aInString) {return NS_ERROR_NULL_POINTER;}
nsresult res = NS_OK;
// for now, we always cancel editor handling of insert text.
// rules code always does the insertion
*aCancel = PR_TRUE;
if (mBogusNode || (PR_TRUE==aTypeInState.IsAnySet()))
{
res = TransactionFactory::GetNewTransaction(PlaceholderTxn::GetCID(), (EditTxn **)aTxn);
if (NS_FAILED(res)) { return res; }
if (!*aTxn) { return NS_ERROR_NULL_POINTER; }
(*aTxn)->SetName(InsertTextTxn::gInsertTextTxnName);
mEditor->Do(*aTxn);
}
PRBool bCancel;
res = WillInsert(aSelection, &bCancel);
if (NS_SUCCEEDED(res) && (!bCancel))
{
if (PR_TRUE==aTypeInState.IsAnySet())
{ // for every property that is set, insert a new inline style node
res = CreateStyleForInsertText(aSelection, aTypeInState);
if (NS_FAILED(res)) { return res; }
}
res = mEditor->InsertTextImpl(*aInString);
}
return res;
}

View File

@ -151,8 +151,23 @@ protected:
/** creates a bogus text node if the document has no editable content */
nsresult CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection);
/** enforce selection must be inside PRE node */
nsresult PinSelectionInPRE(nsIDOMSelection *aSelection);
/** returns a truncated insertion string if insertion would place us
over aMaxLength */
nsresult TruncateInsertionIfNeeded(nsIDOMSelection *aSelection,
const nsString *aInString,
nsString *aOutString,
PRInt32 aMaxLength);
/** Echo's the insertion text into the password buffer, and converts
insertion text to '*'s */
nsresult EchoInsertionToPWBuff(nsIDOMSelection *aSelection, nsString *aOutString);
/** do the actual text insertion */
nsresult DoTextInsertion(nsIDOMSelection *aSelection,
PRBool *aCancel,
PlaceholderTxn **aTxn,
const nsString *aInString,
TypeInState aTypeInState);
// data
nsHTMLEditor *mEditor; // note that we do not refcount the editor

View File

@ -146,14 +146,16 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection,
TypeInState typeInState,
PRInt32 aMaxLength)
{ if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
// initialize out param
*aCancel = PR_FALSE;
*aCancel = PR_TRUE;
nsresult res;
char specialChars[] = {'\t',' ',nbsp,'\n',0};
mEditor->BeginTransaction(); // we have to batch this in case there are returns
// Insert Break txns don't auto merge with insert text txns
// we have to batch this in case there are returns
// Insert Break txns don't auto merge with insert text txns
nsAutoEditBatch beginBatching(mEditor);
// strategy: there are simple cases and harder cases. The harder cases
// we handle recursively by breaking them into a series of simple cases.
@ -165,54 +167,52 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection,
// 5) a run of chars containing no spaces, nbsp's, tabs, or returns
char nbspStr[2] = {nbsp, 0};
// is it a solo tab?
if (*inString == "\t" )
{
res = InsertTab(aSelection,aCancel,aTxn,outString);
}
// is it a solo space?
else if (*inString == " ")
{
res = InsertSpace(aSelection,aCancel,aTxn,outString);
}
// is it a solo nbsp?
else if (*inString == nbspStr)
{
res = InsertSpace(aSelection,aCancel,aTxn,outString);
}
// is it a solo return?
else if (*inString == "\n")
{
// special case - cancel default handling
*aCancel = PR_TRUE;
res = mEditor->InsertBreak();
}
else
{
// is it an innocous run of chars? no spaces, nbsps, returns, tabs?
PRInt32 pos = inString->FindCharInSet(specialChars);
if (pos == -1)
nsString theString(*inString); // copy instr for now
PRInt32 pos = theString.FindCharInSet(specialChars);
while (theString.Length())
{
// no special chars, easy case
res = nsTextEditRules::WillInsertText(aSelection, aCancel, aTxn, inString, outString, typeInState, aMaxLength);
}
else
{
// else we need to break it up into two parts and recurse
*aCancel = PR_TRUE;
nsString firstString;
nsString restOfString(*inString);
PRBool bCancel;
nsString partialString;
// if first char is special, then use just it
if (pos == 0) pos = 1;
inString->Left(firstString, pos);
restOfString.Cut(0, pos);
if (NS_SUCCEEDED(mEditor->InsertText(firstString)))
{
res = mEditor->InsertText(restOfString);
}
if (pos == -1) pos = theString.Length();
theString.Left(partialString, pos);
theString.Cut(0, pos);
// is it a solo tab?
if (partialString == "\t" )
{
res = InsertTab(aSelection,&bCancel,aTxn,outString);
if (NS_FAILED(res)) return res;
res = DoTextInsertion(aSelection, aCancel, aTxn, outString, typeInState);
}
// is it a solo space?
else if (partialString == " ")
{
res = InsertSpace(aSelection,&bCancel,aTxn,outString);
if (NS_FAILED(res)) return res;
res = DoTextInsertion(aSelection, aCancel, aTxn, outString, typeInState);
}
// is it a solo nbsp?
else if (partialString == nbspStr)
{
res = InsertSpace(aSelection,&bCancel,aTxn,outString);
if (NS_FAILED(res)) return res;
res = DoTextInsertion(aSelection, aCancel, aTxn, outString, typeInState);
}
// is it a solo return?
else if (partialString == "\n")
{
res = mEditor->InsertBreak();
}
else
{
res = DoTextInsertion(aSelection, aCancel, aTxn, &partialString, typeInState);
}
if (NS_FAILED(res)) return res;
pos = theString.FindCharInSet(specialChars);
}
}
mEditor->EndTransaction();
return res;
}
@ -224,6 +224,8 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel)
*aCancel = PR_FALSE;
nsresult res;
res = WillInsert(aSelection, aCancel);
if (NS_FAILED(res)) return res;
// if the selection isn't collapsed, delete it.
PRBool bCollapsed;
@ -235,7 +237,7 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel)
if (NS_FAILED(res)) return res;
}
//smart splitting rules
// smart splitting rules
nsCOMPtr<nsIDOMNode> node;
PRInt32 offset;
PRBool isPRE;
@ -251,7 +253,7 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel)
{
nsString theString = "\n";
*aCancel = PR_TRUE;
return mEditor->InsertText(theString);
return mEditor->InsertTextImpl(theString);
}
nsCOMPtr<nsIDOMNode> blockParent;
@ -263,7 +265,7 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel)
if (!blockParent) return NS_ERROR_FAILURE;
// headers: put selection after the header
// headers: close (or split) header
if (IsHeader(blockParent))
{
res = ReturnInHeader(aSelection, blockParent, node, offset);
@ -286,8 +288,7 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel)
return NS_OK;
}
return WillInsert(aSelection, aCancel);
return res;
}
@ -426,10 +427,9 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection, nsIEditor::ESe
return NS_OK;
}
// else do default
return NS_OK;
}
// else do default
return NS_OK;
}
// else we have a non collapsed selection
@ -829,21 +829,16 @@ nsHTMLEditRules::WillIndent(nsIDOMSelection *aSelection, PRBool *aCancel)
if (NS_FAILED(res)) return res;
// some logic for putting list items into nested lists...
if (IsListItem(curNode))
if (IsList(curParent))
{
if (!curList || transitionList[i])
{
nsAutoString quoteType("ol"); // XXX - get correct list type
if (mEditor->CanContainTag(curParent,quoteType))
{
res = mEditor->CreateNode(quoteType, curParent, offset, getter_AddRefs(curList));
if (NS_FAILED(res)) return res;
// curQuote is now the correct thing to put curNode in
}
else
{
printf("trying to put a list in a bad place\n");
}
nsAutoString listTag;
nsEditor::GetTagString(curParent,listTag);
// create a new nested list of correct type
res = mEditor->CreateNode(listTag, curParent, offset, getter_AddRefs(curList));
if (NS_FAILED(res)) return res;
// curList is now the correct thing to put curNode in
}
// tuck the node into the end of the active list
PRUint32 listLen;
@ -935,7 +930,78 @@ nsHTMLEditRules::WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel)
res = nsEditor::GetNodeLocation(curNode, &curParent, &offset);
if (NS_FAILED(res)) return res;
if (transitionList[i])
if (IsList(curParent)) // move node out of list
{
if (IsList(curNode)) // just unwrap this sublist
{
res = RemoveContainer(curNode);
if (NS_FAILED(res)) return res;
}
else // we are moving a list item, but not whole list
{
// if it's first or last list item, dont need to split the list
// otherwise we do.
nsCOMPtr<nsIDOMNode> curParPar;
PRInt32 parOffset;
res = nsEditor::GetNodeLocation(curParent, &curParPar, &parOffset);
if (NS_FAILED(res)) return res;
PRBool bIsFirstListItem;
res = IsFirstEditableChild(curNode, &bIsFirstListItem);
if (NS_FAILED(res)) return res;
PRBool bIsLastListItem;
res = IsLastEditableChild(curNode, &bIsLastListItem);
if (NS_FAILED(res)) return res;
if (!bIsFirstListItem && !bIsLastListItem)
{
// split the list
nsCOMPtr<nsIDOMNode> newBlock;
res = mEditor->SplitNode(curParent, offset, getter_AddRefs(newBlock));
if (NS_FAILED(res)) return res;
}
if (!bIsFirstListItem) parOffset++;
res = mEditor->DeleteNode(curNode);
if (NS_FAILED(res)) return res;
res = mEditor->InsertNode(curNode, curParPar, parOffset);
if (NS_FAILED(res)) return res;
// convert list items to divs if we promoted them out of list
if (!IsList(curParPar) && IsListItem(curNode))
{
nsAutoString blockType("div");
nsCOMPtr<nsIDOMNode> newBlock;
res = ReplaceContainer(curNode,&newBlock,blockType);
if (NS_FAILED(res)) return res;
}
}
}
else if (IsList(curNode)) // node is a list, but parent is non-list: move list items out
{
nsCOMPtr<nsIDOMNode> child;
curNode->GetLastChild(getter_AddRefs(child));
while (child)
{
res = mEditor->DeleteNode(child);
if (NS_FAILED(res)) return res;
res = mEditor->InsertNode(child, curParent, offset);
if (NS_FAILED(res)) return res;
if (IsListItem(child))
{
nsAutoString blockType("div");
nsCOMPtr<nsIDOMNode> newBlock;
res = ReplaceContainer(child,&newBlock,blockType);
if (NS_FAILED(res)) return res;
}
curNode->GetLastChild(getter_AddRefs(child));
}
}
else if (transitionList[i]) // not list related - look for enclosing blockquotes and remove
{
// look for a blockquote somewhere above us and remove it.
// this is a hack until i think about outdent for real.
@ -2391,4 +2457,65 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString
}
nsresult
nsHTMLEditRules::IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst)
{
// check parms
if (!aOutIsFirst || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutIsFirst = PR_FALSE;
// find first editable child and compare it to aNode
nsCOMPtr<nsIDOMNode> parent;
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
if (!parent) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> child;
parent->GetFirstChild(getter_AddRefs(child));
if (!child) return NS_ERROR_FAILURE;
if (!mEditor->IsEditable(child))
{
nsCOMPtr<nsIDOMNode> tmp;
res = mEditor->GetNextNode(child, PR_TRUE, getter_AddRefs(tmp));
if (NS_FAILED(res)) return res;
if (!tmp) return NS_ERROR_FAILURE;
child = tmp;
}
*aOutIsFirst = (child == aNode);
return res;
}
nsresult
nsHTMLEditRules::IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast)
{
// check parms
if (!aOutIsLast || !aNode) return NS_ERROR_NULL_POINTER;
// init out parms
*aOutIsLast = PR_FALSE;
// find last editable child and compare it to aNode
nsCOMPtr<nsIDOMNode> parent;
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
if (!parent) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> child;
parent->GetLastChild(getter_AddRefs(child));
if (!child) return NS_ERROR_FAILURE;
if (!mEditor->IsEditable(child))
{
nsCOMPtr<nsIDOMNode> tmp;
res = mEditor->GetPriorNode(child, PR_TRUE, getter_AddRefs(tmp));
if (NS_FAILED(res)) return res;
if (!tmp) return NS_ERROR_FAILURE;
child = tmp;
}
*aOutIsLast = (child == aNode);
return res;
}

View File

@ -108,6 +108,9 @@ protected:
nsresult RemoveContainer(nsIDOMNode *inNode);
nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, nsString &aNodeType);
nsresult IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst);
nsresult IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast);
};
#endif //nsHTMLEditRules_h__

View File

@ -3507,18 +3507,19 @@ nsresult nsHTMLEditor::GetTextSelectionOffsets(nsIDOMSelection *aSelection,
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
range->GetCommonParent(getter_AddRefs(parentNode));
}
else {
parentNode = do_QueryInterface(startNode);
}
else
{
parentNode = do_QueryInterface(startNode);
}
nsCOMPtr<nsIContentIterator> iter;
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
nsIContentIterator::GetIID(),
getter_AddRefs(iter));
if (NS_FAILED(result)) return result;
if (!iter) return NS_ERROR_NULL_POINTER;
if (NS_FAILED(result)) return result;
if (!iter) return NS_ERROR_NULL_POINTER;
PRUint32 totalLength=0;
nsCOMPtr<nsIDOMCharacterData>textNode;
nsCOMPtr<nsIContent>blockParentContent = do_QueryInterface(parentNode);

View File

@ -75,8 +75,8 @@ nsTextEditRules::Init(nsHTMLEditor *aEditor, PRUint32 aFlags)
nsCOMPtr<nsIDOMSelection> selection;
mEditor->GetSelection(getter_AddRefs(selection));
NS_ASSERTION(selection, "editor cannot get selection");
nsresult result = CreateBogusNodeIfNeeded(selection); // this method handles null selection, which should never happen anyway
return result;
nsresult res = CreateBogusNodeIfNeeded(selection); // this method handles null selection, which should never happen anyway
return res;
}
NS_IMETHODIMP
@ -263,93 +263,32 @@ nsTextEditRules::WillInsertText(nsIDOMSelection *aSelection,
if (!aSelection || !aCancel || !aInString || !aOutString) {return NS_ERROR_NULL_POINTER;}
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
nsresult result;
nsString inString = *aInString; // we might want to mutate the input
// before setting the output, do that in a local var
if ((-1 != aMaxLength) && (mFlags & nsIHTMLEditor::eEditorPlaintextMask))
{
// Get the current text length.
// Get the length of inString.
// Get the length of the selection.
// If selection is collapsed, it is length 0.
// Subtract the length of the selection from the len(doc)
// since we'll delete the selection on insert.
// This is resultingDocLength.
// If (resultingDocLength) is at or over max, cancel the insert
// If (resultingDocLength) + (length of input) > max,
// set aOutString to subset of inString so length = max
PRInt32 docLength;
result = mEditor->GetDocumentLength(&docLength);
if (NS_FAILED(result)) { return result; }
PRInt32 start, end;
result = mEditor->GetTextSelectionOffsets(aSelection, start, end);
if (NS_FAILED(result)) { return result; }
PRInt32 selectionLength = end-start;
if (selectionLength<0) { selectionLength *= (-1); }
PRInt32 resultingDocLength = docLength - selectionLength;
if (resultingDocLength >= aMaxLength)
{
*aOutString = "";
*aCancel = PR_TRUE;
return result;
}
else
{
PRInt32 inCount = inString.Length();
if ((inCount+resultingDocLength) > aMaxLength)
{
inString.Truncate(aMaxLength-resultingDocLength);
}
}
}
nsresult res;
// initialize out params
*aCancel = PR_FALSE;
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
{
// manage the password buffer
PRInt32 start, end;
result = mEditor->GetTextSelectionOffsets(aSelection, start, end);
NS_ASSERTION((NS_SUCCEEDED(result)), "getTextSelectionOffsets failed!");
mPasswordText.Insert(inString, start);
char *password = mPasswordText.ToNewCString();
printf("mPasswordText is %s\n", password);
delete [] password;
// change the output to '*' only
PRInt32 length = inString.Length();
PRInt32 i;
for (i=0; i<length; i++)
*aOutString += '*';
}
else
{
*aOutString = inString;
}
*aCancel = PR_TRUE;
*aOutString = *aInString;
if (mBogusNode || (PR_TRUE==aTypeInState.IsAnySet()))
// handle docs with a max length
res = TruncateInsertionIfNeeded(aSelection, aInString, aOutString, aMaxLength);
if (NS_FAILED(res)) return res;
if (aOutString->Length())
{
result = TransactionFactory::GetNewTransaction(PlaceholderTxn::GetCID(), (EditTxn **)aTxn);
if (NS_FAILED(result)) { return result; }
if (!*aTxn) { return NS_ERROR_NULL_POINTER; }
(*aTxn)->SetName(InsertTextTxn::gInsertTextTxnName);
mEditor->Do(*aTxn);
}
result = WillInsert(aSelection, aCancel);
if (NS_SUCCEEDED(result) && (PR_FALSE==*aCancel))
{
if (PR_TRUE==aTypeInState.IsAnySet())
{ // for every property that is set, insert a new inline style node
result = CreateStyleForInsertText(aSelection, aTypeInState);
// handle password field docs
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
{
res = EchoInsertionToPWBuff(aSelection, aOutString);
if (NS_FAILED(res)) return res;
}
// do text insertion
PRBool bCancel;
res = DoTextInsertion(aSelection, &bCancel, aTxn, aOutString, aTypeInState);
if (NS_FAILED(res)) return res;
}
return result;
return res;
}
nsresult
@ -371,8 +310,8 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
// Otherwise, create the text node and the new inline style parents.
nsCOMPtr<nsIDOMNode>anchor;
PRInt32 offset;
nsresult result = aSelection->GetAnchorNode( getter_AddRefs(anchor));
if (NS_SUCCEEDED(result) && NS_SUCCEEDED(aSelection->GetAnchorOffset(&offset)) && anchor)
nsresult res = aSelection->GetAnchorNode( getter_AddRefs(anchor));
if (NS_SUCCEEDED(res) && NS_SUCCEEDED(aSelection->GetAnchorOffset(&offset)) && anchor)
{
nsCOMPtr<nsIDOMCharacterData>anchorAsText;
anchorAsText = do_QueryInterface(anchor);
@ -382,7 +321,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
// create an empty text node by splitting the selected text node according to offset
if (0==offset)
{
result = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
res = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
}
else
{
@ -391,7 +330,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
if (length==(PRUint32)offset)
{
// newTextNode will be the left node
result = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
res = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
// but we want the right node in this case
newTextNode = do_QueryInterface(anchor);
}
@ -399,21 +338,21 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
{
// splitting anchor twice sets newTextNode as an empty text node between
// two halves of the original text node
result = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
if (NS_SUCCEEDED(result)) {
result = mEditor->SplitNode(anchorAsText, 0, getter_AddRefs(newTextNode));
res = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
if (NS_SUCCEEDED(res)) {
res = mEditor->SplitNode(anchorAsText, 0, getter_AddRefs(newTextNode));
}
}
}
// now we have the new text node we are going to insert into.
// create style nodes or move it up the content hierarchy as needed.
if ((NS_SUCCEEDED(result)) && newTextNode)
if ((NS_SUCCEEDED(res)) && newTextNode)
{
nsCOMPtr<nsIDOMNode>newStyleNode;
if (aTypeInState.IsSet(NS_TYPEINSTATE_BOLD))
{
if (PR_TRUE==aTypeInState.GetBold()) {
result = InsertStyleNode(newTextNode, nsIEditProperty::b, aSelection, getter_AddRefs(newStyleNode));
res = InsertStyleNode(newTextNode, nsIEditProperty::b, aSelection, getter_AddRefs(newStyleNode));
}
else {
printf("not yet implemented, make not bold in a bold context\n");
@ -422,7 +361,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
if (aTypeInState.IsSet(NS_TYPEINSTATE_ITALIC))
{
if (PR_TRUE==aTypeInState.GetItalic()) {
result = InsertStyleNode(newTextNode, nsIEditProperty::i, aSelection, getter_AddRefs(newStyleNode));
res = InsertStyleNode(newTextNode, nsIEditProperty::i, aSelection, getter_AddRefs(newStyleNode));
}
else
{
@ -432,7 +371,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
if (aTypeInState.IsSet(NS_TYPEINSTATE_UNDERLINE))
{
if (PR_TRUE==aTypeInState.GetUnderline()) {
result = InsertStyleNode(newTextNode, nsIEditProperty::u, aSelection, getter_AddRefs(newStyleNode));
res = InsertStyleNode(newTextNode, nsIEditProperty::u, aSelection, getter_AddRefs(newStyleNode));
}
else
{
@ -445,7 +384,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
aTypeInState.GetFontColor(value);
nsAutoString attr;
nsIEditProperty::color->ToString(attr);
result = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
res = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
}
if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTFACE))
{
@ -453,7 +392,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
aTypeInState.GetFontFace(value);
nsAutoString attr;
nsIEditProperty::face->ToString(attr);
result = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
res = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
}
if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTSIZE))
{
@ -461,7 +400,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
aTypeInState.GetFontSize(value);
nsAutoString attr;
nsIEditProperty::size->ToString(attr);
result = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
res = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
}
}
}
@ -500,7 +439,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta
}
}
}
return result;
return res;
}
nsresult
@ -509,23 +448,23 @@ nsTextEditRules::CreateFontStyleForInsertText(nsIDOMNode *aNewTextNode,
const nsString &aValue,
nsIDOMSelection *aSelection)
{
nsresult result = NS_OK;
nsresult res = NS_OK;
nsCOMPtr<nsIDOMNode>newStyleNode;
if (0!=aValue.Length())
{
result = InsertStyleNode(aNewTextNode, nsIEditProperty::font, aSelection, getter_AddRefs(newStyleNode));
if (NS_FAILED(result)) return result;
res = InsertStyleNode(aNewTextNode, nsIEditProperty::font, aSelection, getter_AddRefs(newStyleNode));
if (NS_FAILED(res)) return res;
if (!newStyleNode) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMElement>element = do_QueryInterface(newStyleNode);
if (element) {
result = mEditor->SetAttribute(element, aAttr, aValue);
res = mEditor->SetAttribute(element, aAttr, aValue);
}
}
else
{
printf("not yet implemented, undo font in an font context\n");
}
return result;
return res;
}
nsresult
@ -537,33 +476,33 @@ nsTextEditRules::InsertStyleNode(nsIDOMNode *aNode,
NS_ASSERTION(aNode && aTag, "bad args");
if (!aNode || !aTag) { return NS_ERROR_NULL_POINTER; }
nsresult result;
nsresult res;
nsCOMPtr<nsIDOMNode>parent;
aNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(result)) return result;
if (NS_FAILED(res)) return res;
if (!parent) return NS_ERROR_NULL_POINTER;
PRInt32 offsetInParent;
result = nsEditor::GetChildOffset(aNode, parent, offsetInParent);
if (NS_FAILED(result)) return result;
res = nsEditor::GetChildOffset(aNode, parent, offsetInParent);
if (NS_FAILED(res)) return res;
nsAutoString tag;
aTag->ToString(tag);
result = mEditor->CreateNode(tag, parent, offsetInParent, aNewNode);
if (NS_FAILED(result)) return result;
res = mEditor->CreateNode(tag, parent, offsetInParent, aNewNode);
if (NS_FAILED(res)) return res;
if (!aNewNode) return NS_ERROR_NULL_POINTER;
result = mEditor->DeleteNode(aNode);
if (NS_SUCCEEDED(result))
res = mEditor->DeleteNode(aNode);
if (NS_SUCCEEDED(res))
{
result = mEditor->InsertNode(aNode, *aNewNode, 0);
if (NS_SUCCEEDED(result)) {
res = mEditor->InsertNode(aNode, *aNewNode, 0);
if (NS_SUCCEEDED(res)) {
if (aSelection) {
result = aSelection->Collapse(aNode, 0);
res = aSelection->Collapse(aNode, 0);
}
}
}
return result;
return res;
}
@ -573,24 +512,24 @@ nsTextEditRules::InsertStyleAndNewTextNode(nsIDOMNode *aParentNode, nsIAtom *aTa
NS_ASSERTION(aParentNode && aTag, "bad args");
if (!aParentNode || !aTag) { return NS_ERROR_NULL_POINTER; }
nsresult result;
nsresult res;
// if the selection already points to a text node, just call InsertStyleNode()
if (aSelection)
{
nsCOMPtr<nsIDOMNode>anchor;
PRInt32 offset;
result = aSelection->GetAnchorNode(getter_AddRefs(anchor));
if (NS_FAILED(result)) return result;
res = aSelection->GetAnchorNode(getter_AddRefs(anchor));
if (NS_FAILED(res)) return res;
if (!anchor) return NS_ERROR_NULL_POINTER;
result = aSelection->GetAnchorOffset(&offset);
if (NS_FAILED(result)) return result;
res = aSelection->GetAnchorOffset(&offset);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMCharacterData>anchorAsText;
anchorAsText = do_QueryInterface(anchor);
if (anchorAsText)
{
nsCOMPtr<nsIDOMNode> newStyleNode;
result = InsertStyleNode(anchor, aTag, aSelection, getter_AddRefs(newStyleNode));
return result;
res = InsertStyleNode(anchor, aTag, aSelection, getter_AddRefs(newStyleNode));
return res;
}
}
// if we get here, there is no selected text node so we create one.
@ -598,30 +537,30 @@ nsTextEditRules::InsertStyleAndNewTextNode(nsIDOMNode *aParentNode, nsIAtom *aTa
aTag->ToString(tag);
nsCOMPtr<nsIDOMNode>newStyleNode;
nsCOMPtr<nsIDOMNode>newTextNode;
result = mEditor->CreateNode(tag, aParentNode, 0, getter_AddRefs(newStyleNode));
if (NS_FAILED(result)) return result;
res = mEditor->CreateNode(tag, aParentNode, 0, getter_AddRefs(newStyleNode));
if (NS_FAILED(res)) return res;
if (!newStyleNode) return NS_ERROR_NULL_POINTER;
result = mEditor->CreateNode(nsEditor::GetTextNodeTag(), newStyleNode, 0, getter_AddRefs(newTextNode));
if (NS_FAILED(result)) return result;
res = mEditor->CreateNode(nsEditor::GetTextNodeTag(), newStyleNode, 0, getter_AddRefs(newTextNode));
if (NS_FAILED(res)) return res;
if (!newTextNode) return NS_ERROR_NULL_POINTER;
if (aSelection) {
result = aSelection->Collapse(newTextNode, 0);
res = aSelection->Collapse(newTextNode, 0);
}
return result;
return res;
}
nsresult
nsTextEditRules::WillSetTextProperty(nsIDOMSelection *aSelection, PRBool *aCancel)
{
nsresult result = NS_OK;
nsresult res = NS_OK;
// XXX: should probably return a success value other than NS_OK that means "not allowed"
if (nsIHTMLEditor::eEditorPlaintextMask & mFlags) {
*aCancel = PR_TRUE;
}
return result;
return res;
}
nsresult
@ -633,13 +572,13 @@ nsTextEditRules::DidSetTextProperty(nsIDOMSelection *aSelection, nsresult aResul
nsresult
nsTextEditRules::WillRemoveTextProperty(nsIDOMSelection *aSelection, PRBool *aCancel)
{
nsresult result = NS_OK;
nsresult res = NS_OK;
// XXX: should probably return a success value other than NS_OK that means "not allowed"
if (nsIHTMLEditor::eEditorPlaintextMask & mFlags) {
*aCancel = PR_TRUE;
}
return result;
return res;
}
nsresult
@ -697,37 +636,37 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection,
nsIEditor::ESelectionCollapseDirection aCollapsedAction,
nsresult aResult)
{
nsresult result = aResult; // if aResult is an error, we just return it
nsresult res = aResult; // if aResult is an error, we just return it
if (!aSelection) { return NS_ERROR_NULL_POINTER; }
PRBool isCollapsed;
aSelection->GetIsCollapsed(&isCollapsed);
NS_ASSERTION(PR_TRUE==isCollapsed, "selection not collapsed after delete selection.");
// if the delete selection resulted in no content
// insert a special bogus text node with a &nbsp; character in it.
if (NS_SUCCEEDED(result)) // only do this work if DeleteSelection completed successfully
if (NS_SUCCEEDED(res)) // only do this work if DeleteSelection completed successfully
{
result = CreateBogusNodeIfNeeded(aSelection);
res = CreateBogusNodeIfNeeded(aSelection);
// if we don't have an empty document, check the selection to see if any collapsing is necessary
if (!mBogusNode)
{
nsCOMPtr<nsIDOMNode>anchor;
PRInt32 offset;
result = aSelection->GetAnchorNode(getter_AddRefs(anchor));
if (NS_FAILED(result)) return result;
res = aSelection->GetAnchorNode(getter_AddRefs(anchor));
if (NS_FAILED(res)) return res;
if (!anchor) return NS_ERROR_NULL_POINTER;
result = aSelection->GetAnchorOffset(&offset);
if (NS_FAILED(result)) return result;
res = aSelection->GetAnchorOffset(&offset);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMNodeList> anchorChildren;
result = anchor->GetChildNodes(getter_AddRefs(anchorChildren));
res = anchor->GetChildNodes(getter_AddRefs(anchorChildren));
nsCOMPtr<nsIDOMNode> selectedNode;
if ((NS_SUCCEEDED(result)) && anchorChildren) {
result = anchorChildren->Item(offset, getter_AddRefs(selectedNode));
if ((NS_SUCCEEDED(res)) && anchorChildren) {
res = anchorChildren->Item(offset, getter_AddRefs(selectedNode));
}
else {
selectedNode = do_QueryInterface(anchor);
}
if ((NS_SUCCEEDED(result)) && selectedNode)
if ((NS_SUCCEEDED(res)) && selectedNode)
{
nsCOMPtr<nsIDOMCharacterData>selectedNodeAsText;
selectedNodeAsText = do_QueryInterface(selectedNode);
@ -744,10 +683,10 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection,
PRUint32 siblingLength; // the length of siblingNode before the join
siblingNodeAsText->GetLength(&siblingLength);
nsCOMPtr<nsIDOMNode> parentNode;
result = selectedNode->GetParentNode(getter_AddRefs(parentNode));
if (NS_FAILED(result)) return result;
res = selectedNode->GetParentNode(getter_AddRefs(parentNode));
if (NS_FAILED(res)) return res;
if (!parentNode) return NS_ERROR_NULL_POINTER;
result = mEditor->JoinNodes(siblingNode, selectedNode, parentNode);
res = mEditor->JoinNodes(siblingNode, selectedNode, parentNode);
// selectedNode will remain after the join, siblingNode is removed
}
}
@ -761,22 +700,22 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection,
PRUint32 selectedNodeLength; // the length of siblingNode before the join
selectedNodeAsText->GetLength(&selectedNodeLength);
nsCOMPtr<nsIDOMNode> parentNode;
result = selectedNode->GetParentNode(getter_AddRefs(parentNode));
if (NS_FAILED(result)) return result;
res = selectedNode->GetParentNode(getter_AddRefs(parentNode));
if (NS_FAILED(res)) return res;
if (!parentNode) return NS_ERROR_NULL_POINTER;
result = mEditor->JoinNodes(selectedNode, siblingNode, parentNode);
if (NS_FAILED(result)) return result;
res = mEditor->JoinNodes(selectedNode, siblingNode, parentNode);
if (NS_FAILED(res)) return res;
// selectedNode will remain after the join, siblingNode is removed
// set selection
result = aSelection->Collapse(siblingNode, selectedNodeLength);
res = aSelection->Collapse(siblingNode, selectedNodeLength);
}
}
}
}
}
}
return result;
return res;
}
nsresult
@ -789,7 +728,7 @@ nsTextEditRules::WillUndo(nsIDOMSelection *aSelection, PRBool *aCancel)
return NS_OK;
}
/* the idea here is to see if the magic empty node has suddenly reappeared as the result of the undo.
/* the idea here is to see if the magic empty node has suddenly reappeared as the res of the undo.
* if it has, set our state so we remember it.
* There is a tradeoff between doing here and at redo, or doing it everywhere else that might care.
* Since undo and redo are relatively rare, it makes sense to take the (small) performance hit here.
@ -797,9 +736,9 @@ nsTextEditRules::WillUndo(nsIDOMSelection *aSelection, PRBool *aCancel)
nsresult
nsTextEditRules:: DidUndo(nsIDOMSelection *aSelection, nsresult aResult)
{
nsresult result = aResult; // if aResult is an error, we return it.
nsresult res = aResult; // if aResult is an error, we return it.
if (!aSelection) { return NS_ERROR_NULL_POINTER; }
if (NS_SUCCEEDED(result))
if (NS_SUCCEEDED(res))
{
if (mBogusNode) {
mBogusNode = do_QueryInterface(nsnull);
@ -808,11 +747,11 @@ nsTextEditRules:: DidUndo(nsIDOMSelection *aSelection, nsresult aResult)
{
nsCOMPtr<nsIDOMNode>node;
PRInt32 offset;
result = aSelection->GetAnchorNode(getter_AddRefs(node));
if (NS_FAILED(result)) return result;
res = aSelection->GetAnchorNode(getter_AddRefs(node));
if (NS_FAILED(res)) return res;
if (!node) return NS_ERROR_NULL_POINTER;
result = aSelection->GetAnchorOffset(&offset);
if (NS_FAILED(result)) return result;
res = aSelection->GetAnchorOffset(&offset);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(node);
if (element)
@ -825,11 +764,11 @@ nsTextEditRules:: DidUndo(nsIDOMSelection *aSelection, nsresult aResult)
}
}
nsCOMPtr<nsIDOMNode> temp;
result = node->GetParentNode(getter_AddRefs(temp));
res = node->GetParentNode(getter_AddRefs(temp));
node = do_QueryInterface(temp);
}
}
return result;
return res;
}
nsresult
@ -845,9 +784,9 @@ nsTextEditRules::WillRedo(nsIDOMSelection *aSelection, PRBool *aCancel)
nsresult
nsTextEditRules::DidRedo(nsIDOMSelection *aSelection, nsresult aResult)
{
nsresult result = aResult; // if aResult is an error, we return it.
nsresult res = aResult; // if aResult is an error, we return it.
if (!aSelection) { return NS_ERROR_NULL_POINTER; }
if (NS_SUCCEEDED(result))
if (NS_SUCCEEDED(res))
{
if (mBogusNode) {
mBogusNode = do_QueryInterface(nsnull);
@ -856,11 +795,11 @@ nsTextEditRules::DidRedo(nsIDOMSelection *aSelection, nsresult aResult)
{
nsCOMPtr<nsIDOMNode>node;
PRInt32 offset;
result = aSelection->GetAnchorNode(getter_AddRefs(node));
if (NS_FAILED(result)) return result;
res = aSelection->GetAnchorNode(getter_AddRefs(node));
if (NS_FAILED(res)) return res;
if (!node) return NS_ERROR_NULL_POINTER;
result = aSelection->GetAnchorOffset(&offset);
if (NS_FAILED(result)) return result;
res = aSelection->GetAnchorOffset(&offset);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(node);
if (element)
@ -873,11 +812,11 @@ nsTextEditRules::DidRedo(nsIDOMSelection *aSelection, nsresult aResult)
}
}
nsCOMPtr<nsIDOMNode> temp;
result = node->GetParentNode(getter_AddRefs(temp));
res = node->GetParentNode(getter_AddRefs(temp));
node = do_QueryInterface(temp);
}
}
return result;
return res;
}
nsresult
@ -913,8 +852,8 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection)
if (!mEditor) { return NS_ERROR_NULL_POINTER; }
nsCOMPtr<nsIDOMElement> bodyElement;
nsresult result = mEditor->GetBodyElement(getter_AddRefs(bodyElement));
if (NS_FAILED(result)) return result;
nsresult res = mEditor->GetBodyElement(getter_AddRefs(bodyElement));
if (NS_FAILED(res)) return res;
if (!bodyElement) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode>bodyNode = do_QueryInterface(bodyElement);
@ -923,8 +862,8 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection)
// if no editable content is found, insert the bogus node
PRBool needsBogusContent=PR_TRUE;
nsCOMPtr<nsIDOMNode>bodyChild;
result = bodyNode->GetFirstChild(getter_AddRefs(bodyChild));
while ((NS_SUCCEEDED(result)) && bodyChild)
res = bodyNode->GetFirstChild(getter_AddRefs(bodyChild));
while ((NS_SUCCEEDED(res)) && bodyChild)
{
if (PR_TRUE==mEditor->IsEditable(bodyChild))
{
@ -938,15 +877,15 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection)
if (PR_TRUE==needsBogusContent)
{
// set mBogusNode to be the newly created <P>
result = mEditor->CreateNode(nsAutoString("P"), bodyNode, 0,
res = mEditor->CreateNode(nsAutoString("P"), bodyNode, 0,
getter_AddRefs(mBogusNode));
if (NS_FAILED(result)) return result;
if (NS_FAILED(res)) return res;
if (!mBogusNode) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode>newTNode;
result = mEditor->CreateNode(nsEditor::GetTextNodeTag(), mBogusNode, 0,
res = mEditor->CreateNode(nsEditor::GetTextNodeTag(), mBogusNode, 0,
getter_AddRefs(newTNode));
if (NS_FAILED(result)) return result;
if (NS_FAILED(res)) return res;
if (!newTNode) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMCharacterData>newNodeAsText;
@ -968,6 +907,119 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection)
newPElement->SetAttribute(att, val);
}
}
return result;
return res;
}
nsresult
nsTextEditRules::TruncateInsertionIfNeeded(nsIDOMSelection *aSelection,
const nsString *aInString,
nsString *aOutString,
PRInt32 aMaxLength)
{
if (!aSelection || !aInString || !aOutString) {return NS_ERROR_NULL_POINTER;}
nsresult res = NS_OK;
*aOutString = *aInString;
if ((-1 != aMaxLength) && (mFlags & nsIHTMLEditor::eEditorPlaintextMask))
{
// Get the current text length.
// Get the length of inString.
// Get the length of the selection.
// If selection is collapsed, it is length 0.
// Subtract the length of the selection from the len(doc)
// since we'll delete the selection on insert.
// This is resultingDocLength.
// If (resultingDocLength) is at or over max, cancel the insert
// If (resultingDocLength) + (length of input) > max,
// set aOutString to subset of inString so length = max
PRInt32 docLength;
res = mEditor->GetDocumentLength(&docLength);
if (NS_FAILED(res)) { return res; }
PRInt32 start, end;
res = mEditor->GetTextSelectionOffsets(aSelection, start, end);
if (NS_FAILED(res)) { return res; }
PRInt32 selectionLength = end-start;
if (selectionLength<0) { selectionLength *= (-1); }
PRInt32 resultingDocLength = docLength - selectionLength;
if (resultingDocLength >= aMaxLength)
{
*aOutString = "";
return res;
}
else
{
PRInt32 inCount = aOutString->Length();
if ((inCount+resultingDocLength) > aMaxLength)
{
aOutString->Truncate(aMaxLength-resultingDocLength);
}
}
}
return res;
}
nsresult
nsTextEditRules::EchoInsertionToPWBuff(nsIDOMSelection *aSelection, nsString *aOutString)
{
if (!aSelection || !aOutString) {return NS_ERROR_NULL_POINTER;}
// manage the password buffer
PRInt32 start, end;
nsresult res = mEditor->GetTextSelectionOffsets(aSelection, start, end);
NS_ASSERTION((NS_SUCCEEDED(res)), "getTextSelectionOffsets failed!");
mPasswordText.Insert(*aOutString, start);
#ifdef NS_DEBUG
char *password = mPasswordText.ToNewCString();
printf("mPasswordText is %s\n", password);
delete [] password;
#endif
// change the output to '*' only
PRInt32 length = aOutString->Length();
PRInt32 i;
for (i=0; i<length; i++)
*aOutString += '*';
return res;
}
nsresult
nsTextEditRules::DoTextInsertion(nsIDOMSelection *aSelection,
PRBool *aCancel,
PlaceholderTxn **aTxn,
const nsString *aInString,
TypeInState aTypeInState)
{
if (!aSelection || !aCancel || !aInString) {return NS_ERROR_NULL_POINTER;}
nsresult res = NS_OK;
// for now, we always cancel editor handling of insert text.
// rules code always does the insertion
*aCancel = PR_TRUE;
if (mBogusNode || (PR_TRUE==aTypeInState.IsAnySet()))
{
res = TransactionFactory::GetNewTransaction(PlaceholderTxn::GetCID(), (EditTxn **)aTxn);
if (NS_FAILED(res)) { return res; }
if (!*aTxn) { return NS_ERROR_NULL_POINTER; }
(*aTxn)->SetName(InsertTextTxn::gInsertTextTxnName);
mEditor->Do(*aTxn);
}
PRBool bCancel;
res = WillInsert(aSelection, &bCancel);
if (NS_SUCCEEDED(res) && (!bCancel))
{
if (PR_TRUE==aTypeInState.IsAnySet())
{ // for every property that is set, insert a new inline style node
res = CreateStyleForInsertText(aSelection, aTypeInState);
if (NS_FAILED(res)) { return res; }
}
res = mEditor->InsertTextImpl(*aInString);
}
return res;
}

View File

@ -151,8 +151,23 @@ protected:
/** creates a bogus text node if the document has no editable content */
nsresult CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection);
/** enforce selection must be inside PRE node */
nsresult PinSelectionInPRE(nsIDOMSelection *aSelection);
/** returns a truncated insertion string if insertion would place us
over aMaxLength */
nsresult TruncateInsertionIfNeeded(nsIDOMSelection *aSelection,
const nsString *aInString,
nsString *aOutString,
PRInt32 aMaxLength);
/** Echo's the insertion text into the password buffer, and converts
insertion text to '*'s */
nsresult EchoInsertionToPWBuff(nsIDOMSelection *aSelection, nsString *aOutString);
/** do the actual text insertion */
nsresult DoTextInsertion(nsIDOMSelection *aSelection,
PRBool *aCancel,
PlaceholderTxn **aTxn,
const nsString *aInString,
TypeInState aTypeInState);
// data
nsHTMLEditor *mEditor; // note that we do not refcount the editor