From 99de773e6809c99cfee85d2a740d3179a720f6eb Mon Sep 17 00:00:00 2001 From: "jfrancis%netscape.com" Date: Tue, 24 Aug 1999 08:56:51 +0000 Subject: [PATCH] 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 --- mozilla/editor/base/nsHTMLEditRules.cpp | 261 ++++++++--- mozilla/editor/base/nsHTMLEditRules.h | 3 + mozilla/editor/base/nsHTMLEditor.cpp | 13 +- mozilla/editor/base/nsTextEditRules.cpp | 408 ++++++++++-------- mozilla/editor/base/nsTextEditRules.h | 19 +- .../editor/libeditor/html/nsHTMLEditRules.cpp | 261 ++++++++--- .../editor/libeditor/html/nsHTMLEditRules.h | 3 + .../editor/libeditor/html/nsHTMLEditor.cpp | 13 +- .../editor/libeditor/text/nsTextEditRules.cpp | 408 ++++++++++-------- .../editor/libeditor/text/nsTextEditRules.h | 19 +- 10 files changed, 902 insertions(+), 506 deletions(-) diff --git a/mozilla/editor/base/nsHTMLEditRules.cpp b/mozilla/editor/base/nsHTMLEditRules.cpp index 32ae4d4e162..6c1289ad668 100644 --- a/mozilla/editor/base/nsHTMLEditRules.cpp +++ b/mozilla/editor/base/nsHTMLEditRules.cpp @@ -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 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 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 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 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 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 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 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 parent; + nsresult res = aNode->GetParentNode(getter_AddRefs(parent)); + if (NS_FAILED(res)) return res; + if (!parent) return NS_ERROR_FAILURE; + nsCOMPtr child; + parent->GetFirstChild(getter_AddRefs(child)); + if (!child) return NS_ERROR_FAILURE; + if (!mEditor->IsEditable(child)) + { + nsCOMPtr 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 parent; + nsresult res = aNode->GetParentNode(getter_AddRefs(parent)); + if (NS_FAILED(res)) return res; + if (!parent) return NS_ERROR_FAILURE; + nsCOMPtr child; + parent->GetLastChild(getter_AddRefs(child)); + if (!child) return NS_ERROR_FAILURE; + + if (!mEditor->IsEditable(child)) + { + nsCOMPtr 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; +} diff --git a/mozilla/editor/base/nsHTMLEditRules.h b/mozilla/editor/base/nsHTMLEditRules.h index 95477e05067..283f214292d 100644 --- a/mozilla/editor/base/nsHTMLEditRules.h +++ b/mozilla/editor/base/nsHTMLEditRules.h @@ -108,6 +108,9 @@ protected: nsresult RemoveContainer(nsIDOMNode *inNode); nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr *outNode, nsString &aNodeType); + nsresult IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst); + nsresult IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast); + }; #endif //nsHTMLEditRules_h__ diff --git a/mozilla/editor/base/nsHTMLEditor.cpp b/mozilla/editor/base/nsHTMLEditor.cpp index 1ad4683d781..aa7a29358ba 100644 --- a/mozilla/editor/base/nsHTMLEditor.cpp +++ b/mozilla/editor/base/nsHTMLEditor.cpp @@ -3507,18 +3507,19 @@ nsresult nsHTMLEditor::GetTextSelectionOffsets(nsIDOMSelection *aSelection, nsCOMPtr range( do_QueryInterface(currentItem) ); range->GetCommonParent(getter_AddRefs(parentNode)); } - else { - parentNode = do_QueryInterface(startNode); - } + else + { + parentNode = do_QueryInterface(startNode); + } nsCOMPtr 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; nsCOMPtrtextNode; nsCOMPtrblockParentContent = do_QueryInterface(parentNode); diff --git a/mozilla/editor/base/nsTextEditRules.cpp b/mozilla/editor/base/nsTextEditRules.cpp index e6fd63d5704..7cc36f319a1 100644 --- a/mozilla/editor/base/nsTextEditRules.cpp +++ b/mozilla/editor/base/nsTextEditRules.cpp @@ -75,8 +75,8 @@ nsTextEditRules::Init(nsHTMLEditor *aEditor, PRUint32 aFlags) nsCOMPtr 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; iLength()) { - 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. nsCOMPtranchor; 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) { nsCOMPtranchorAsText; 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) { nsCOMPtrnewStyleNode; 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; nsCOMPtrnewStyleNode; 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; nsCOMPtrelement = 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; nsCOMPtrparent; 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) { nsCOMPtranchor; 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; nsCOMPtranchorAsText; anchorAsText = do_QueryInterface(anchor); if (anchorAsText) { nsCOMPtr 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); nsCOMPtrnewStyleNode; nsCOMPtrnewTextNode; - 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   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) { nsCOMPtranchor; 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 anchorChildren; - result = anchor->GetChildNodes(getter_AddRefs(anchorChildren)); + res = anchor->GetChildNodes(getter_AddRefs(anchorChildren)); nsCOMPtr 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) { nsCOMPtrselectedNodeAsText; 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 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 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) { nsCOMPtrnode; 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; nsCOMPtrelement; element = do_QueryInterface(node); if (element) @@ -825,11 +764,11 @@ nsTextEditRules:: DidUndo(nsIDOMSelection *aSelection, nsresult aResult) } } nsCOMPtr 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) { nsCOMPtrnode; 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; nsCOMPtrelement; element = do_QueryInterface(node); if (element) @@ -873,11 +812,11 @@ nsTextEditRules::DidRedo(nsIDOMSelection *aSelection, nsresult aResult) } } nsCOMPtr 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 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; nsCOMPtrbodyNode = 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; nsCOMPtrbodyChild; - 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

- 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; nsCOMPtrnewTNode; - 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; nsCOMPtrnewNodeAsText; @@ -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; iSetName(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; +} diff --git a/mozilla/editor/base/nsTextEditRules.h b/mozilla/editor/base/nsTextEditRules.h index 58c77dd517e..f989d2ddafa 100644 --- a/mozilla/editor/base/nsTextEditRules.h +++ b/mozilla/editor/base/nsTextEditRules.h @@ -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 diff --git a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp index 32ae4d4e162..6c1289ad668 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp @@ -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 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 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 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 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 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 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 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 parent; + nsresult res = aNode->GetParentNode(getter_AddRefs(parent)); + if (NS_FAILED(res)) return res; + if (!parent) return NS_ERROR_FAILURE; + nsCOMPtr child; + parent->GetFirstChild(getter_AddRefs(child)); + if (!child) return NS_ERROR_FAILURE; + if (!mEditor->IsEditable(child)) + { + nsCOMPtr 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 parent; + nsresult res = aNode->GetParentNode(getter_AddRefs(parent)); + if (NS_FAILED(res)) return res; + if (!parent) return NS_ERROR_FAILURE; + nsCOMPtr child; + parent->GetLastChild(getter_AddRefs(child)); + if (!child) return NS_ERROR_FAILURE; + + if (!mEditor->IsEditable(child)) + { + nsCOMPtr 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; +} diff --git a/mozilla/editor/libeditor/html/nsHTMLEditRules.h b/mozilla/editor/libeditor/html/nsHTMLEditRules.h index 95477e05067..283f214292d 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditRules.h +++ b/mozilla/editor/libeditor/html/nsHTMLEditRules.h @@ -108,6 +108,9 @@ protected: nsresult RemoveContainer(nsIDOMNode *inNode); nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr *outNode, nsString &aNodeType); + nsresult IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst); + nsresult IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast); + }; #endif //nsHTMLEditRules_h__ diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp index 1ad4683d781..aa7a29358ba 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp @@ -3507,18 +3507,19 @@ nsresult nsHTMLEditor::GetTextSelectionOffsets(nsIDOMSelection *aSelection, nsCOMPtr range( do_QueryInterface(currentItem) ); range->GetCommonParent(getter_AddRefs(parentNode)); } - else { - parentNode = do_QueryInterface(startNode); - } + else + { + parentNode = do_QueryInterface(startNode); + } nsCOMPtr 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; nsCOMPtrtextNode; nsCOMPtrblockParentContent = do_QueryInterface(parentNode); diff --git a/mozilla/editor/libeditor/text/nsTextEditRules.cpp b/mozilla/editor/libeditor/text/nsTextEditRules.cpp index e6fd63d5704..7cc36f319a1 100644 --- a/mozilla/editor/libeditor/text/nsTextEditRules.cpp +++ b/mozilla/editor/libeditor/text/nsTextEditRules.cpp @@ -75,8 +75,8 @@ nsTextEditRules::Init(nsHTMLEditor *aEditor, PRUint32 aFlags) nsCOMPtr 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; iLength()) { - 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. nsCOMPtranchor; 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) { nsCOMPtranchorAsText; 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) { nsCOMPtrnewStyleNode; 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; nsCOMPtrnewStyleNode; 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; nsCOMPtrelement = 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; nsCOMPtrparent; 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) { nsCOMPtranchor; 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; nsCOMPtranchorAsText; anchorAsText = do_QueryInterface(anchor); if (anchorAsText) { nsCOMPtr 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); nsCOMPtrnewStyleNode; nsCOMPtrnewTextNode; - 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   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) { nsCOMPtranchor; 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 anchorChildren; - result = anchor->GetChildNodes(getter_AddRefs(anchorChildren)); + res = anchor->GetChildNodes(getter_AddRefs(anchorChildren)); nsCOMPtr 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) { nsCOMPtrselectedNodeAsText; 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 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 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) { nsCOMPtrnode; 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; nsCOMPtrelement; element = do_QueryInterface(node); if (element) @@ -825,11 +764,11 @@ nsTextEditRules:: DidUndo(nsIDOMSelection *aSelection, nsresult aResult) } } nsCOMPtr 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) { nsCOMPtrnode; 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; nsCOMPtrelement; element = do_QueryInterface(node); if (element) @@ -873,11 +812,11 @@ nsTextEditRules::DidRedo(nsIDOMSelection *aSelection, nsresult aResult) } } nsCOMPtr 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 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; nsCOMPtrbodyNode = 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; nsCOMPtrbodyChild; - 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

- 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; nsCOMPtrnewTNode; - 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; nsCOMPtrnewNodeAsText; @@ -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; iSetName(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; +} diff --git a/mozilla/editor/libeditor/text/nsTextEditRules.h b/mozilla/editor/libeditor/text/nsTextEditRules.h index 58c77dd517e..f989d2ddafa 100644 --- a/mozilla/editor/libeditor/text/nsTextEditRules.h +++ b/mozilla/editor/libeditor/text/nsTextEditRules.h @@ -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