diff --git a/editor/base/PlaceholderTxn.cpp b/editor/base/PlaceholderTxn.cpp index 6201acfcaad..4e8f353b2a4 100644 --- a/editor/base/PlaceholderTxn.cpp +++ b/editor/base/PlaceholderTxn.cpp @@ -18,6 +18,8 @@ #include "PlaceholderTxn.h" #include "nsVoidArray.h" +#include "nsHTMLEditor.h" +#include "nsIPresShell.h" #if defined(NS_DEBUG) && defined(DEBUG_buster) static PRBool gNoisy = PR_TRUE; @@ -26,10 +28,11 @@ static const PRBool gNoisy = PR_FALSE; #endif -PlaceholderTxn::PlaceholderTxn() - : EditAggregateTxn() +PlaceholderTxn::PlaceholderTxn() : EditAggregateTxn(), + mPresShellWeak(nsnull), + mAbsorb(PR_TRUE), + mForwarding(nsnull) { - mAbsorb=PR_TRUE; SetTransactionDescriptionID( kTransactionID ); /* log description initialized in parent constructor */ } @@ -39,39 +42,153 @@ PlaceholderTxn::~PlaceholderTxn() { } +NS_IMPL_ADDREF_INHERITED(PlaceholderTxn, EditAggregateTxn) +NS_IMPL_RELEASE_INHERITED(PlaceholderTxn, EditAggregateTxn) + +//NS_IMPL_QUERY_INTERFACE_INHERITED(Class, Super, AdditionalInterface) +NS_IMETHODIMP PlaceholderTxn::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (!aInstancePtr) return NS_ERROR_NULL_POINTER; + + if (aIID.Equals(nsIAbsorbingTransaction::GetIID())) { + *aInstancePtr = (nsISupports*)(nsIAbsorbingTransaction*)(this); + NS_ADDREF_THIS(); + return NS_OK; + } + if (aIID.Equals(nsCOMTypeInfo::GetIID())) { + *aInstancePtr = (nsISupports*)(nsISupportsWeakReference*) this; + NS_ADDREF_THIS(); + return NS_OK; + } + return EditAggregateTxn::QueryInterface(aIID, aInstancePtr); +} + +NS_IMETHODIMP PlaceholderTxn::Init(nsWeakPtr aPresShellWeak, nsIAtom *aName, + nsIDOMNode *aStartNode, PRInt32 aStartOffset) +{ + NS_ASSERTION(aPresShellWeak, "bad args"); + if (!aPresShellWeak) return NS_ERROR_NULL_POINTER; + + mPresShellWeak = aPresShellWeak; + mName = aName; + mStartNode = do_QueryInterface(aStartNode); + mStartOffset = aStartOffset; + return NS_OK; +} + NS_IMETHODIMP PlaceholderTxn::Do(void) { if (gNoisy) { printf("PlaceholderTxn Do\n"); } return NS_OK; } +NS_IMETHODIMP PlaceholderTxn::Undo(void) +{ + // using this to debug + return EditAggregateTxn::Undo(); +} + + NS_IMETHODIMP PlaceholderTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransaction) { + if (!aDidMerge || !aTransaction) return NS_ERROR_NULL_POINTER; + // set out param default value - if (nsnull!=aDidMerge) - *aDidMerge=PR_FALSE; - nsresult result = NS_OK; - if ((nsnull!=aDidMerge) && (nsnull!=aTransaction)) + *aDidMerge=PR_FALSE; + + nsresult res = NS_OK; + + if (mForwarding) { - EditTxn *editTxn = (EditTxn*)aTransaction; //XXX: hack, not safe! need nsIEditTransaction! - if (PR_TRUE==mAbsorb) - { // yep, it's one of ours. Assimilate it. - AppendChild(editTxn); - *aDidMerge = PR_TRUE; - if (gNoisy) { printf("Placeholder txn assimilated %p\n", aTransaction); } - } - else - { // let our last child txn make the choice - PRInt32 count = mChildren->Count(); - if (0 plcTxn;// = do_QueryInterface(editTxn); + // cant do_QueryInterface() above due to our broken transaction interfaces. + // instead have to brute it below. ugh. + editTxn->QueryInterface(nsIAbsorbingTransaction::GetIID(), getter_AddRefs(plcTxn)); + if (plcTxn) { - EditTxn *lastTxn = (EditTxn*)(mChildren->ElementAt(count-1)); - if (lastTxn) + nsIAtom *atom; + plcTxn->GetTxnName(&atom); + if (atom && (atom == nsHTMLEditor::gTypingTxnName)) { - lastTxn->Merge(aDidMerge, aTransaction); + nsCOMPtr otherTxnStartNode; + PRInt32 otherTxnStartOffset; + res = plcTxn->GetStartNodeAndOffset(&otherTxnStartNode, &otherTxnStartOffset); + if (NS_FAILED(res)) return res; + + if ((otherTxnStartNode == mEndNode) && (otherTxnStartOffset == mEndOffset)) + { + mAbsorb = PR_TRUE; // we need to start absorbing again + plcTxn->ForwardEndBatchTo(this); + AppendChild(editTxn); + *aDidMerge = PR_TRUE; + } } } } } - return result; + return res; } + +NS_IMETHODIMP PlaceholderTxn::GetTxnName(nsIAtom **aName) +{ + return GetName(aName); +} + +NS_IMETHODIMP PlaceholderTxn::GetStartNodeAndOffset(nsCOMPtr *aTxnStartNode, PRInt32 *aTxnStartOffset) +{ + if (!aTxnStartNode || !aTxnStartOffset) return NS_ERROR_NULL_POINTER; + *aTxnStartNode = mStartNode; + *aTxnStartOffset = mStartOffset; + return NS_OK; +} + +NS_IMETHODIMP PlaceholderTxn::EndPlaceHolderBatch() +{ + mAbsorb = PR_FALSE; + + if (mForwarding) + { + nsCOMPtr plcTxn = do_QueryReferent(mForwarding); + if (plcTxn) plcTxn->EndPlaceHolderBatch(); + } + + // if we are a typing transaction, remember our selection state + if (mName.get() == nsHTMLEditor::gTypingTxnName) + { + nsCOMPtr ps = do_QueryReferent(mPresShellWeak); + if (!ps) return NS_ERROR_NOT_INITIALIZED; + nsCOMPtr selection; + nsresult res = ps->GetSelection(SELECTION_NORMAL, getter_AddRefs(selection)); + if (NS_FAILED(res)) return res; + if (!selection) return NS_ERROR_NULL_POINTER; + res = nsEditor::GetStartNodeAndOffset(selection, &mEndNode, &mEndOffset); + if (NS_FAILED(res)) return res; + } + return NS_OK; +}; + +NS_IMETHODIMP PlaceholderTxn::ForwardEndBatchTo(nsIAbsorbingTransaction *aForwardingAddress) +{ + mForwarding = getter_AddRefs( NS_GetWeakReference(aForwardingAddress) ); + return NS_OK; +} + + + + + diff --git a/editor/base/PlaceholderTxn.h b/editor/base/PlaceholderTxn.h index 3d214e34d30..5ad13ec7d02 100644 --- a/editor/base/PlaceholderTxn.h +++ b/editor/base/PlaceholderTxn.h @@ -20,24 +20,36 @@ #define AggregatePlaceholderTxn_h__ #include "EditAggregateTxn.h" +#include "nsIAbsorbingTransaction.h" +#include "nsIDOMNode.h" +#include "nsCOMPtr.h" +#include "nsWeakPtr.h" +#include "nsWeakReference.h" #define PLACEHOLDER_TXN_CID \ {/* {0CE9FB00-D9D1-11d2-86DE-000064657374} */ \ 0x0CE9FB00, 0xD9D1, 0x11d2, \ {0x86, 0xde, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} } +class nsHTMLEditor; + /** * An aggregate transaction that knows how to absorb all subsequent * transactions with the same name. This transaction does not "Do" anything. * But it absorbs other transactions via merge, and can undo/redo the * transactions it has absorbed. */ -class PlaceholderTxn : public EditAggregateTxn + +class PlaceholderTxn : public EditAggregateTxn, + public nsIAbsorbingTransaction, + public nsSupportsWeakReference { public: static const nsIID& GetCID() { static nsIID iid = PLACEHOLDER_TXN_CID; return iid; } + NS_DECL_ISUPPORTS_INHERITED + private: PlaceholderTxn(); @@ -45,11 +57,25 @@ public: virtual ~PlaceholderTxn(); +// ------------ EditAggregateTxn ----------------------- + NS_IMETHOD Do(void); + NS_IMETHOD Undo(void); + NS_IMETHOD Merge(PRBool *aDidMerge, nsITransaction *aTransaction); - NS_IMETHOD SetAbsorb(PRBool aAbsorb); +// ------------ nsIAbsorbingTransaction ----------------------- + + NS_IMETHOD Init(nsWeakPtr aPresShellWeak, nsIAtom *aName, nsIDOMNode *aStartNode, PRInt32 aStartOffset); + + NS_IMETHOD GetTxnName(nsIAtom **aName); + + NS_IMETHOD GetStartNodeAndOffset(nsCOMPtr *aTxnStartNode, PRInt32 *aTxnStartOffset); + + NS_IMETHOD EndPlaceHolderBatch(); + + NS_IMETHOD ForwardEndBatchTo(nsIAbsorbingTransaction *aForwardingAddress); friend class TransactionFactory; @@ -57,14 +83,12 @@ public: protected: - PRBool mAbsorb; - -}; - -inline NS_IMETHODIMP PlaceholderTxn::SetAbsorb(PRBool aAbsorb) -{ - mAbsorb = aAbsorb; - return NS_OK; + /** the presentation shell, which we'll need to get the selection */ + nsWeakPtr mPresShellWeak; // weak reference to the nsIPresShell + PRBool mAbsorb; + nsCOMPtr mStartNode, mEndNode; // selection nodes at beginning and end of operation + PRInt32 mStartOffset, mEndOffset; // selection offsets at beginning and end of operation + nsWeakPtr mForwarding; }; diff --git a/editor/base/nsEditor.cpp b/editor/base/nsEditor.cpp index 828fbef5b3c..d85b6a60706 100644 --- a/editor/base/nsEditor.cpp +++ b/editor/base/nsEditor.cpp @@ -36,6 +36,7 @@ #include "nsIServiceManager.h" #include "nsTransactionManagerCID.h" #include "nsITransactionManager.h" +#include "nsIAbsorbingTransaction.h" #include "nsIPresShell.h" #include "nsIPresContext.h" #include "nsIViewManager.h" @@ -54,6 +55,7 @@ #include "nsIDocumentObserver.h" #include "nsIDocumentStateListener.h" #include "nsIStringStream.h" +#include "nsITextContent.h" #ifdef NECKO #include "nsNeckoUtil.h" @@ -68,6 +70,7 @@ // transactions the editor knows how to build #include "TransactionFactory.h" #include "EditAggregateTxn.h" +#include "PlaceholderTxn.h" #include "ChangeAttributeTxn.h" #include "CreateElementTxn.h" #include "InsertElementTxn.h" @@ -85,6 +88,7 @@ #include "nsEditorCID.h" #include "nsEditor.h" +#include "nsEditorUtils.h" #ifdef HACK_FORCE_REDRAW @@ -143,6 +147,12 @@ nsEditor::nsEditor() , mActionListeners(nsnull) , mDocDirtyState(-1) , mDocWeak(nsnull) +, mPlaceHolderTxn(nsnull) +, mPlaceHolderName(nsnull) +, mPlaceHolderBatch(0) +, mTxnStartNode(nsnull) +, mTxnStartOffset(0) + { //initialize member variables here NS_INIT_REFCNT(); @@ -332,6 +342,31 @@ nsEditor::Do(nsITransaction *aTxn) { if (gNoisy) { printf("Editor::Do ----------\n"); } nsresult result = NS_OK; + + if (mPlaceHolderBatch && !mPlaceHolderTxn) + { + // it's pretty darn amazing how many different types of pointers + // this transcation goes through here. I bet this is a record. + EditTxn *editTxn; + nsCOMPtr plcTxn; + result = TransactionFactory::GetNewTransaction(PlaceholderTxn::GetCID(), &editTxn); + if (NS_FAILED(result)) { return result; } + if (!editTxn) { return NS_ERROR_NULL_POINTER; } + editTxn->QueryInterface(nsIAbsorbingTransaction::GetIID(), getter_AddRefs(plcTxn)); + // have to use line above instead of line below due to our broken + // interface model for transactions. +// plcTxn = do_QueryInterface(editTxn); + // save off weak reference to placeholder txn + mPlaceHolderTxn = getter_AddRefs( NS_GetWeakReference(plcTxn) ); + plcTxn->Init(mPresShellWeak, mPlaceHolderName, mTxnStartNode, mTxnStartOffset); + // we will recurse, but will not hit this case in the nested call + nsCOMPtr theTxn = do_QueryInterface(plcTxn); + nsITransaction* txn = theTxn; + // we want to escape from this routine with a positive refcount + txn->AddRef(); + Do(txn); + } + nsCOMPtrselection; nsresult selectionResult = GetSelection(getter_AddRefs(selection)); if (NS_SUCCEEDED(selectionResult) && selection) { @@ -504,6 +539,72 @@ nsEditor::EndTransaction() return NS_OK; } + +// These two routines are similar to the above, but do not use +// the transaction managers batching feature. Instead we use +// a placeholder transaction to wrap up any further transaction +// while the batch is open. The advantage of this is that +// placeholder transactions can later merge, if needed. Merging +// is unavailable between transaction manager batches. + +NS_IMETHODIMP +nsEditor::BeginPlaceHolderTransaction(nsIAtom *aName) +{ + NS_PRECONDITION(mPlaceHolderBatch >= 0, "negative placeholder batch count!"); + if (!mPlaceHolderBatch) + { + // time to turn on the batch + BeginUpdateViewBatch(); + mPlaceHolderTxn = nsnull; + mPlaceHolderName = aName; + nsCOMPtr selection; + nsresult res = GetSelection(getter_AddRefs(selection)); + if (NS_FAILED(res)) return res; + PRBool collapsed; + res = selection->GetIsCollapsed(&collapsed); + if (NS_FAILED(res)) return res; + if (collapsed) // we cant merge with previous typing if selection not collapsed + { + // need to remember colapsed selection point to Init the placeholder with later. + // this is because we dont actually make the placeholder until we need it, and we + // might have moved the selection as part of the typing processing by then. + res = GetStartNodeAndOffset(selection, &mTxnStartNode, &mTxnStartOffset); + if (NS_FAILED(res)) return res; + } + } + mPlaceHolderBatch++; + + return NS_OK; +} + +NS_IMETHODIMP +nsEditor::EndPlaceHolderTransaction() +{ + NS_PRECONDITION(mPlaceHolderBatch > 0, "zero or negative placeholder batch count when ending batch!"); + if (mPlaceHolderBatch == 1) + { + // time to turn off the batch + EndUpdateViewBatch(); + mTxnStartNode = nsnull; + mTxnStartOffset = 0; + if (mPlaceHolderTxn) // we might have never made a placeholder if no action took place + { + nsCOMPtr plcTxn = do_QueryReferent(mPlaceHolderTxn); + if (plcTxn) + { + plcTxn->EndPlaceHolderBatch(); + } + else // but if we did make one it should be around + { + NS_NOTREACHED("should this ever happen?"); + } + } + } + mPlaceHolderBatch--; + + return NS_OK; +} + // XXX: the rule system should tell us which node to select all on (ie, the root, or the body) NS_IMETHODIMP nsEditor::SelectAll() { @@ -1489,8 +1590,9 @@ NS_IMETHODIMP nsEditor::InsertTextImpl(const nsString& aStringToInsert) result = CreateTxnForInsertText(aStringToInsert, nsnull, &txn); // insert at the current selection if ((NS_SUCCEEDED(result)) && txn) { BeginUpdateViewBatch(); - aggTxn->AppendChild(txn); +// aggTxn->AppendChild(txn); result = Do(aggTxn); + result = Do(txn); EndUpdateViewBatch(); } else if (NS_ERROR_EDITOR_NO_SELECTION==result) { @@ -1769,7 +1871,7 @@ NS_IMETHODIMP nsEditor::CreateTxnForInsertText(const nsString & aStringToInsert, // This may be OK, now that I fixed InsertText so it inserts // at the offset of the selection anchor (i.e., the caret offset) // instead of at offset+1 - PRBool collapsed + PRBool collapsed; result = selection->GetIsCollapsed(&collapsed); if (NS_SUCCEEDED(result) && collapsed) { @@ -2559,8 +2661,8 @@ nsEditor::GetPriorNode(nsIDOMNode *aParentNode, nsresult result = NS_OK; if (!aParentNode || !aResultNode) { return NS_ERROR_NULL_POINTER; } - // if we are at beginning of node than just look before it - if (!aOffset) + // if we are at beginning of node, or it is a textnode, then just look before it + if (!aOffset || IsTextNode(aParentNode)) { return GetPriorNode(aParentNode, aEditableNode, aResultNode); } @@ -2601,6 +2703,14 @@ nsEditor::GetNextNode(nsIDOMNode *aParentNode, nsresult result = NS_OK; if (!aParentNode || !aResultNode) { return NS_ERROR_NULL_POINTER; } + // if aParentNode is a text node, use it's location instead + if (IsTextNode(aParentNode)) + { + nsCOMPtr parent; + nsEditor::GetNodeLocation(aParentNode, &parent, &aOffset); + aParentNode = parent; + aOffset++; // _after_ the text node + } // look at the child at 'aOffset' nsCOMPtr child = GetChildAt(aParentNode, aOffset); if (child) @@ -2828,6 +2938,18 @@ nsEditor::CanContainTag(nsIDOMNode* aParent, const nsString &aTag) return mDTD->CanContain(parentTagEnum, childTagEnum); } +PRBool +nsEditor::IsContainer(nsIDOMNode *aNode) +{ + if (!aNode) return PR_FALSE; + nsAutoString stringTag; + PRInt32 tagEnum; + nsresult res = aNode->GetNodeName(stringTag); + if (NS_FAILED(res)) return PR_FALSE; + res = mDTD->StringTagToIntTag(stringTag,&tagEnum); + if (NS_FAILED(res)) return PR_FALSE; + return mDTD->IsContainer(tagEnum); +} PRBool nsEditor::IsEditable(nsIDOMNode *aNode) @@ -2885,13 +3007,27 @@ nsEditor::IsEditable(nsIDOMNode *aNode) if (NS_FAILED(result) || !resultFrame) { // if it has no frame, it is not editable return PR_FALSE; } - else { // it has a frame, so it is editable + else { + // it has a frame, so it might editable + // but not if it's a formatting whitespace node + if (IsEmptyTextContent(content)) return PR_FALSE; return PR_TRUE; } } return PR_FALSE; // it's not a content object (???) so it's not editable } +PRBool +nsEditor::IsEmptyTextContent(nsIContent* aContent) +{ + PRBool result = PR_FALSE; + nsCOMPtr tc(do_QueryInterface(aContent)); + if (tc) { + tc->IsOnlyWhitespace(&result); + } + return result; +} + nsresult nsEditor::CountEditableChildren(nsIDOMNode *aNode, PRUint32 &outCount) { @@ -3108,7 +3244,7 @@ nsEditor::SetInputMethodText(const nsString& aStringToInsert, nsIPrivateTextRang } else if (NS_ERROR_EDITOR_NO_TEXTNODE==result) { - BeginTransaction(); + nsAutoEditBatch batchIt (this); nsCOMPtr selection; result = GetSelection(getter_AddRefs(selection)); if ((NS_SUCCEEDED(result)) && selection) @@ -3138,8 +3274,6 @@ nsEditor::SetInputMethodText(const nsString& aStringToInsert, nsIPrivateTextRang } } } - - EndTransaction(); } return result; diff --git a/editor/base/nsEditor.h b/editor/base/nsEditor.h index 219c9a1f31a..fdc234c9a3a 100644 --- a/editor/base/nsEditor.h +++ b/editor/base/nsEditor.h @@ -121,6 +121,9 @@ public: NS_IMETHOD BeginTransaction(); NS_IMETHOD EndTransaction(); + NS_IMETHOD BeginPlaceHolderTransaction(nsIAtom *aName); + NS_IMETHOD EndPlaceHolderTransaction(); + // pure virtual, because the definition of 'empty' depends on the doc type NS_IMETHOD GetDocumentIsEmpty(PRBool *aDocumentIsEmpty)=0; @@ -553,11 +556,17 @@ public: static PRBool NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag); /** returns PR_TRUE if aParent can contain a child of type aTag */ - PRBool CanContainTag(nsIDOMNode* aParent, const nsString &aTag); + PRBool CanContainTag(nsIDOMNode* aParent, const nsString &aTag); + /** returns PR_TRUE if aNode is a container */ + PRBool IsContainer(nsIDOMNode *aNode); + /** returns PR_TRUE if aNode is an editable node */ PRBool IsEditable(nsIDOMNode *aNode); + /** returns PR_TRUE if content is an merely formatting whitespacce */ + PRBool IsEmptyTextContent(nsIContent* aContent); + /** counts number of editable child nodes */ nsresult CountEditableChildren(nsIDOMNode *aNode, PRUint32 &outCount); @@ -608,6 +617,11 @@ protected: nsCOMPtr mTxnMgr; nsCOMPtr mEditProperty; nsCOMPtr mLastStyleSheet; // is owning this dangerous? + nsWeakPtr mPlaceHolderTxn; + nsIAtom *mPlaceHolderName; + PRInt32 mPlaceHolderBatch; + nsCOMPtr mTxnStartNode; + PRInt32 mTxnStartOffset; // // data necessary to build IME transactions diff --git a/editor/base/nsEditorUtils.h b/editor/base/nsEditorUtils.h index 5c7c07844b6..5d2c64e4f5b 100644 --- a/editor/base/nsEditorUtils.h +++ b/editor/base/nsEditorUtils.h @@ -25,6 +25,7 @@ #include "nsIDOMNode.h" #include "nsIDOMSelection.h" #include "nsIEditor.h" +#include "nsIAtom.h" class nsAutoEditBatch { @@ -43,11 +44,21 @@ class nsAutoEditMayBatch PRBool mDidBatch; public: nsAutoEditMayBatch( nsIEditor *aEd) : mEd(do_QueryInterface(aEd)), mDidBatch(PR_FALSE) {} - nsAutoEditMayBatch() { if (mEd && mDidBatch) mEd->EndTransaction(); } + ~nsAutoEditMayBatch() { if (mEd && mDidBatch) mEd->EndTransaction(); } void batch() { if (mEd && !mDidBatch) {mEd->BeginTransaction(); mDidBatch=PR_TRUE;} } }; +class nsAutoPlaceHolderBatch +{ + private: + nsCOMPtr mEd; + public: + nsAutoPlaceHolderBatch( nsIEditor *aEd, nsIAtom *atom) : mEd(do_QueryInterface(aEd)) + { if (mEd) mEd->BeginPlaceHolderTransaction(atom); } + ~nsAutoPlaceHolderBatch() { if (mEd) mEd->EndPlaceHolderTransaction(); } +}; + class nsAutoSelectionReset { diff --git a/editor/base/nsHTMLEditRules.cpp b/editor/base/nsHTMLEditRules.cpp index 0211e3c89c4..639d3c465d1 100644 --- a/editor/base/nsHTMLEditRules.cpp +++ b/editor/base/nsHTMLEditRules.cpp @@ -21,9 +21,6 @@ #include "nsEditor.h" #include "nsHTMLEditor.h" -#include "PlaceholderTxn.h" -#include "InsertTextTxn.h" - #include "nsIContent.h" #include "nsIContentIterator.h" #include "nsIDOMNode.h" @@ -90,7 +87,6 @@ nsHTMLEditRules::WillDoAction(nsIDOMSelection *aSelection, case kInsertText: return WillInsertText(aSelection, aCancel, - info->placeTxn, info->inString, info->outString, info->typeInState, @@ -127,11 +123,13 @@ nsHTMLEditRules::DidDoAction(nsIDOMSelection *aSelection, switch (info->action) { - case kInsertBreak: - return NS_OK; + case kUndo: + return nsTextEditRules::DidDoAction(aSelection, aInfo, aResult); + case kRedo: + return nsTextEditRules::DidDoAction(aSelection, aInfo, aResult); } - // clean up any empty nodes in the selection + // other than undo and redo, clean up any empty nodes in the selection CleanUpSelection(aSelection); return nsTextEditRules::DidDoAction(aSelection, aInfo, aResult); @@ -145,7 +143,6 @@ nsHTMLEditRules::DidDoAction(nsIDOMSelection *aSelection, nsresult nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection, PRBool *aCancel, - PlaceholderTxn **aTxn, const nsString *inString, nsString *outString, TypeInState typeInState, @@ -155,7 +152,8 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection, // initialize out param *aCancel = PR_TRUE; nsresult res; - nsAutoEditMayBatch optionalBatch; + nsCOMPtr selNode; + PRInt32 selOffset; char specialChars[] = {'\t',' ',nbsp,'\n',0}; @@ -169,20 +167,27 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection, if (NS_FAILED(res)) return res; } + // get the (collapsed) selection location + res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset); + if (NS_FAILED(res)) return res; + + res = WillInsert(aSelection, aCancel); + if (NS_FAILED(res)) return res; + + // initialize out param + // we want to ignore result of WillInsert() + *aCancel = PR_TRUE; + // split any mailcites in the way - if (1 || mFlags & nsIHTMLEditor::eEditorMailMask) + if (mFlags & nsIHTMLEditor::eEditorMailMask) { - nsCOMPtr citeNode, selNode; - PRInt32 selOffset, newOffset; - res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset); - if (NS_FAILED(res)) return res; + nsCOMPtr citeNode; + PRInt32 newOffset; res = GetTopEnclosingMailCite(selNode, &citeNode); if (NS_FAILED(res)) return res; if (citeNode) { - // turn batching on - optionalBatch.batch(); res = mEditor->SplitNodeDeep(citeNode, selNode, selOffset, &newOffset); if (NS_FAILED(res)) return res; res = citeNode->GetParentNode(getter_AddRefs(selNode)); @@ -192,9 +197,73 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection, } } + // identify the block + nsCOMPtr blockParent; + + if (nsEditor::IsBlockNode(selNode)) + blockParent = selNode; + else + blockParent = mEditor->GetBlockNodeParent(selNode); + if (!blockParent) return NS_ERROR_FAILURE; + + // are we not in a textnode? + if (!mEditor->IsTextNode(selNode)) + { + // find a nearby text node if possible + nsCOMPtr priorNode, nextNode; + res = GetPriorHTMLNode(selNode, selOffset, &priorNode); + if (NS_SUCCEEDED(res) && priorNode && mEditor->IsTextNode(priorNode) + && (blockParent == mEditor->GetBlockNodeParent(priorNode))) + { + // put selection at end of prior node + PRUint32 strLength; + nsCOMPtr textNode = do_QueryInterface(priorNode); + res = textNode->GetLength(&strLength); + if (NS_FAILED(res)) return res; + res = aSelection->Collapse(priorNode, strLength); + if (NS_FAILED(res)) return res; + } + else + { + res = GetNextHTMLNode(selNode, selOffset, &nextNode); + if (NS_SUCCEEDED(res) && nextNode && mEditor->IsTextNode(nextNode) + && (blockParent == mEditor->GetBlockNodeParent(nextNode))) + { + // put selection at begining of next node + res = aSelection->Collapse(nextNode, 0); + if (NS_FAILED(res)) return res; + } + } + + // if we are right after a moz br, delete it and make a new moz div + PRBool needMozDiv = PR_FALSE; + if (priorNode && IsBreak(priorNode) && HasMozAttr(priorNode) + && (blockParent == mEditor->GetBlockNodeParent(priorNode))) + { + needMozDiv = PR_TRUE; + res = mEditor->DeleteNode(priorNode); + if (NS_FAILED(res)) return res; + } + + // if we are directly in a body or (non-moz) div, create a moz-div. + // Also creat one if we detected a prior moz br (see above). + res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset); + if (NS_FAILED(res)) return res; + if (needMozDiv || IsBody(selNode) || IsNormalDiv(selNode)) + { + // wrap things up in a moz-div + nsCOMPtr mozDiv; + res = CreateMozDiv(selNode, selOffset, &mozDiv); + if (NS_FAILED(res)) return res; + // put selection in it + res = aSelection->Collapse(mozDiv, 0); + if (NS_FAILED(res)) return res; + } + } + char nbspStr[2] = {nbsp, 0}; - nsString theString(*inString); // copy instr for now + nsString theString(*inString); // copy instring for now PRInt32 pos = theString.FindCharInSet(specialChars); while (theString.Length()) { @@ -208,23 +277,23 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection, // is it a solo tab? if (partialString == "\t" ) { - res = InsertTab(aSelection,&bCancel,aTxn,outString); + res = InsertTab(aSelection,&bCancel,outString); if (NS_FAILED(res)) return res; - res = DoTextInsertion(aSelection, aCancel, aTxn, outString, typeInState); + res = DoTextInsertion(aSelection, aCancel, outString, typeInState); } // is it a solo space? else if (partialString == " ") { - res = InsertSpace(aSelection,&bCancel,aTxn,outString); + res = InsertSpace(aSelection,&bCancel,outString); if (NS_FAILED(res)) return res; - res = DoTextInsertion(aSelection, aCancel, aTxn, outString, typeInState); + res = DoTextInsertion(aSelection, aCancel, outString, typeInState); } // is it a solo nbsp? else if (partialString == nbspStr) { - res = InsertSpace(aSelection,&bCancel,aTxn,outString); + res = InsertSpace(aSelection,&bCancel,outString); if (NS_FAILED(res)) return res; - res = DoTextInsertion(aSelection, aCancel, aTxn, outString, typeInState); + res = DoTextInsertion(aSelection, aCancel, outString, typeInState); } // is it a solo return? else if (partialString == "\n") @@ -233,7 +302,7 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection, } else { - res = DoTextInsertion(aSelection, aCancel, aTxn, &partialString, typeInState); + res = DoTextInsertion(aSelection, aCancel, &partialString, typeInState); } if (NS_FAILED(res)) return res; pos = theString.FindCharInSet(specialChars); @@ -250,7 +319,6 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel) *aCancel = PR_FALSE; nsresult res; - nsAutoEditMayBatch optionalBatch; res = WillInsert(aSelection, aCancel); if (NS_FAILED(res)) return res; @@ -269,7 +337,7 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel) } // split any mailcites in the way - if (1 || mFlags & nsIHTMLEditor::eEditorMailMask) + if (mFlags & nsIHTMLEditor::eEditorMailMask) { nsCOMPtr citeNode, selNode; PRInt32 selOffset, newOffset; @@ -280,8 +348,6 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel) if (citeNode) { - // turn batching on - optionalBatch.batch(); res = mEditor->SplitNodeDeep(citeNode, selNode, selOffset, &newOffset); if (NS_FAILED(res)) return res; res = citeNode->GetParentNode(getter_AddRefs(selNode)); @@ -310,6 +376,7 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel) return mEditor->InsertTextImpl(theString); } + // identify the block nsCOMPtr blockParent; if (nsEditor::IsBlockNode(node)) @@ -319,8 +386,67 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel) if (!blockParent) return NS_ERROR_FAILURE; + // break action depends on type of block + PRBool bIsMozDiv = IsMozDiv(blockParent); + PRBool bIsNormalDiv = IsNormalDiv(blockParent); + + // body, div, or mozdiv: insert a moz br + if (IsBody(blockParent) || bIsNormalDiv || + (bIsMozDiv && AtEndOfBlock(node, offset, blockParent))) + { + if (bIsMozDiv) + { + // put selection beyond the mozdiv first + nsCOMPtr parent; + PRInt32 pOffset; + res = nsEditor::GetNodeLocation(blockParent, &parent, &pOffset); + if (NS_FAILED(res)) return res; + if (!parent) return NS_ERROR_FAILURE; + res = aSelection->Collapse(parent, pOffset+1); + if (NS_FAILED(res)) return res; + } + nsCOMPtr brNode; + res = mEditor->InsertBR(&brNode); // only inserts a br node + if (NS_FAILED(res)) return res; + // give it special moz attr + nsCOMPtr brElem = do_QueryInterface(brNode); + if (brElem) + { + res = mEditor->SetAttribute(brElem, "type", "_moz"); + if (NS_FAILED(res)) return res; + } + *aCancel = PR_TRUE; + } + else if (bIsMozDiv && AtStartOfBlock(node, offset, blockParent)) + { + // position selection in front of mozdiv, and let default code + // make a normal br + nsCOMPtr parent; + PRInt32 pOffset; + res = nsEditor::GetNodeLocation(blockParent, &parent, &pOffset); + if (NS_FAILED(res)) return res; + if (!parent) return NS_ERROR_FAILURE; + res = aSelection->Collapse(parent, pOffset); + if (NS_FAILED(res)) return res; + } + else if (bIsMozDiv) + { + // we are in the middle of the mozdiv: split it + PRInt32 newOffset; + res = mEditor->SplitNodeDeep( blockParent, node, offset, &newOffset); + if (NS_FAILED(res)) return res; + // put selection at beginning of new mozdiv + nsCOMPtr parent; + blockParent->GetParentNode(getter_AddRefs(parent)); + nsCOMPtr newDiv = nsEditor::GetChildAt(parent, newOffset); + if (!newDiv || !IsMozDiv(newDiv)) return NS_ERROR_FAILURE; + res = aSelection->Collapse(newDiv, 0); + if (NS_FAILED(res)) return res; + *aCancel = PR_TRUE; + } + // headers: close (or split) header - if (IsHeader(blockParent)) + else if (IsHeader(blockParent)) { res = ReturnInHeader(aSelection, blockParent, node, offset); *aCancel = PR_TRUE; @@ -328,14 +454,14 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel) } // paragraphs: special rules to look for
s - if (IsParagraph(blockParent)) + else if (IsParagraph(blockParent)) { res = ReturnInParagraph(aSelection, blockParent, node, offset, aCancel); return NS_OK; } // list items: special rules to make new list items - if (IsListItem(blockParent)) + else if (IsListItem(blockParent)) { res = ReturnInListItem(aSelection, blockParent, node, offset); *aCancel = PR_TRUE; @@ -411,10 +537,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection, nsIEditor::ESe if (!leftParent || !rightParent) return NS_OK; // bail to default - nsCOMPtr leftAtom = mEditor->GetTag(leftParent); - nsCOMPtr rightAtom = mEditor->GetTag(rightParent); - - if (leftAtom.get() == rightAtom.get()) + if (mEditor->NodesSameType(leftParent, rightParent)) { nsCOMPtr topParent; leftParent->GetParentNode(getter_AddRefs(topParent)); @@ -454,10 +577,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection, nsIEditor::ESe // are the blocks of same type? nsCOMPtr leftParent = mEditor->GetBlockNodeParent(node); nsCOMPtr rightParent = mEditor->GetBlockNodeParent(nextNode); - nsCOMPtr leftAtom = mEditor->GetTag(leftParent); - nsCOMPtr rightAtom = mEditor->GetTag(rightParent); - - if (leftAtom.get() == rightAtom.get()) + if (mEditor->NodesSameType(leftParent, rightParent)) { nsCOMPtr topParent; leftParent->GetParentNode(getter_AddRefs(topParent)); @@ -561,10 +681,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection, nsIEditor::ESe // bail to default if blocks aren't siblings if (leftBlockParent.get() != rightBlockParent.get()) return NS_OK; - nsCOMPtr leftAtom = mEditor->GetTag(leftParent); - nsCOMPtr rightAtom = mEditor->GetTag(rightParent); - - if (leftAtom.get() == rightAtom.get()) + if (mEditor->NodesSameType(leftParent, rightParent)) { nsCOMPtr topParent; leftParent->GetParentNode(getter_AddRefs(topParent)); @@ -810,8 +927,15 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo } else { - nsAutoString listItemType = "li"; - res = InsertContainerAbove(curNode, &listItem, listItemType); + // don't wrap li around a moz-div. instead replace moz-div with li + if (IsMozDiv(curNode)) + { + res = ReplaceContainer(curNode, &listItem, "li"); + } + else + { + res = InsertContainerAbove(curNode, &listItem, "li"); + } if (NS_FAILED(res)) return res; if (nsEditor::IsInlineNode(curNode)) prevListItem = listItem; @@ -1291,6 +1415,7 @@ nsHTMLEditRules::IsHeader(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsHeader"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if ( (tag == "h1") || (tag == "h2") || (tag == "h3") || @@ -1313,6 +1438,7 @@ nsHTMLEditRules::IsParagraph(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsParagraph"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if (tag == "p") { return PR_TRUE; @@ -1330,6 +1456,7 @@ nsHTMLEditRules::IsListItem(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsListItem"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if (tag == "li") { return PR_TRUE; @@ -1347,6 +1474,7 @@ nsHTMLEditRules::IsList(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsList"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if ( (tag == "ol") || (tag == "ul") ) { @@ -1365,6 +1493,7 @@ nsHTMLEditRules::IsOrderedList(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsOrderedList"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if (tag == "ol") { return PR_TRUE; @@ -1382,6 +1511,7 @@ nsHTMLEditRules::IsUnorderedList(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsUnorderedList"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if (tag == "ul") { return PR_TRUE; @@ -1399,6 +1529,7 @@ nsHTMLEditRules::IsBreak(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsBreak"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if (tag == "br") { return PR_TRUE; @@ -1416,6 +1547,7 @@ nsHTMLEditRules::IsBody(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsBody"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if (tag == "body") { return PR_TRUE; @@ -1433,6 +1565,7 @@ nsHTMLEditRules::IsBlockquote(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsBlockquote"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if (tag == "blockquote") { return PR_TRUE; @@ -1441,6 +1574,24 @@ nsHTMLEditRules::IsBlockquote(nsIDOMNode *node) } +/////////////////////////////////////////////////////////////////////////// +// IsAnchor: true if node an html anchor node +// +PRBool +nsHTMLEditRules::IsAnchor(nsIDOMNode *node) +{ + NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsAnchor"); + nsAutoString tag; + nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); + if (tag == "a") + { + return PR_TRUE; + } + return PR_FALSE; +} + + /////////////////////////////////////////////////////////////////////////// // IsDiv: true if node an html div node // @@ -1450,6 +1601,7 @@ nsHTMLEditRules::IsDiv(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsDiv"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if (tag == "div") { return PR_TRUE; @@ -1458,6 +1610,51 @@ nsHTMLEditRules::IsDiv(nsIDOMNode *node) } +/////////////////////////////////////////////////////////////////////////// +// IsNormalDiv: true if node an html div node, without type = _moz +// +PRBool +nsHTMLEditRules::IsNormalDiv(nsIDOMNode *node) +{ + if (IsDiv(node) && !HasMozAttr(node)) return PR_TRUE; + return PR_FALSE; +} + + +/////////////////////////////////////////////////////////////////////////// +// IsMozDiv: true if node an html div node with type = _moz +// +PRBool +nsHTMLEditRules::IsMozDiv(nsIDOMNode *node) +{ + if (IsDiv(node) && HasMozAttr(node)) return PR_TRUE; + return PR_FALSE; +} + + +/////////////////////////////////////////////////////////////////////////// +// HasMozAttr: true if node has type attribute = _moz +// (used to indicate the div's and br's we use in +// mail compose rules) +// +PRBool +nsHTMLEditRules::HasMozAttr(nsIDOMNode *node) +{ + NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::HasMozAttr"); + nsCOMPtr elem = do_QueryInterface(node); + if (elem) + { + nsAutoString typeAttrName("type"); + nsAutoString typeAttrVal; + nsresult res = elem->GetAttribute(typeAttrName, typeAttrVal); + typeAttrVal.ToLowerCase(); + if (NS_SUCCEEDED(res) && (typeAttrVal == "_moz")) + return PR_TRUE; + } + return PR_FALSE; +} + + /////////////////////////////////////////////////////////////////////////// // IsMailCite: true if node an html blockquote with type=cite // @@ -1471,6 +1668,7 @@ nsHTMLEditRules::IsMailCite(nsIDOMNode *node) nsAutoString typeAttrName("type"); nsAutoString typeAttrVal; nsresult res = bqElem->GetAttribute(typeAttrName, typeAttrVal); + typeAttrVal.ToLowerCase(); if (NS_SUCCEEDED(res)) { if (typeAttrVal == "cite") @@ -1544,6 +1742,17 @@ nsHTMLEditRules::IsEmptyNode(nsIDOMNode *aNode, PRBool *outIsEmptyNode) return NS_OK; } + // if it's not a text node (handled above) and it's not a container, + // then we dont call it empty (it's an
, or
, etc). + // Also, if it's an anchor then dont treat it as empty - even though + // anchors are containers, named anchors are "empty" but we don't + // want to treat them as such. + if (!mEditor->IsContainer(aNode) || IsAnchor(aNode)) + { + *outIsEmptyNode = PR_FALSE; + return NS_OK; + } + // iterate over node. if no children, or all children are either // empty text nodes or non-editable, then node qualifies as empty nsCOMPtr iter; @@ -1593,6 +1802,24 @@ nsHTMLEditRules::IsEmptyNode(nsIDOMNode *aNode, PRBool *outIsEmptyNode) } +/////////////////////////////////////////////////////////////////////////// +// CreateMozDiv: makes a div with type = _moz +// +nsresult +nsHTMLEditRules::CreateMozDiv(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr *outDiv) +{ + if (!inParent || !outDiv) return NS_ERROR_NULL_POINTER; + nsAutoString divType= "div"; + *outDiv = nsnull; + nsresult res = mEditor->CreateNode(divType, inParent, inOffset, getter_AddRefs(*outDiv)); + if (NS_FAILED(res)) return res; + // give it special moz attr + nsCOMPtr mozDivElem = do_QueryInterface(*outDiv); + res = mEditor->SetAttribute(mozDivElem, "type", "_moz"); + return res; +} + + /////////////////////////////////////////////////////////////////////////// // GetPriorHTMLNode: returns the previous editable leaf node, if there is // one within the @@ -1757,6 +1984,48 @@ nsHTMLEditRules::IsLastNode(nsIDOMNode *aNode) } +/////////////////////////////////////////////////////////////////////////// +// AtStartOfBlock: is node/offset at the start of the editable material in this block? +// +PRBool +nsHTMLEditRules::AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock) +{ + nsCOMPtr nodeAsText = do_QueryInterface(aNode); + if (nodeAsText && aOffset) return PR_FALSE; // there are chars in front of us + + nsCOMPtr priorNode; + nsresult res = GetPriorHTMLNode(aNode, aOffset, &priorNode); + if (NS_FAILED(res)) return PR_TRUE; + if (!priorNode) return PR_TRUE; + nsCOMPtr blockParent = mEditor->GetBlockNodeParent(priorNode); + if (blockParent && (blockParent.get() == aBlock)) return PR_FALSE; + return PR_TRUE; +} + + +/////////////////////////////////////////////////////////////////////////// +// AtEndOfBlock: is node/offset at the end of the editable material in this block? +// +PRBool +nsHTMLEditRules::AtEndOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock) +{ + nsCOMPtr nodeAsText = do_QueryInterface(aNode); + if (nodeAsText) + { + PRUint32 strLength; + nodeAsText->GetLength(&strLength); + if (strLength > aOffset) return PR_FALSE; // there are chars in after us + } + nsCOMPtr nextNode; + nsresult res = GetNextHTMLNode(aNode, aOffset, &nextNode); + if (NS_FAILED(res)) return PR_TRUE; + if (!nextNode) return PR_TRUE; + nsCOMPtr blockParent = mEditor->GetBlockNodeParent(nextNode); + if (blockParent && (blockParent.get() == aBlock)) return PR_FALSE; + return PR_TRUE; +} + + /////////////////////////////////////////////////////////////////////////// // GetPromotedPoint: figure out where a start or end point for a block // operation really is @@ -2171,7 +2440,7 @@ nsHTMLEditRules::RemoveContainer(nsIDOMNode *inNode) nsresult nsHTMLEditRules::InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr *outNode, - nsString &aNodeType) + const nsString &aNodeType) { if (!inNode || !outNode) return NS_ERROR_NULL_POINTER; @@ -2207,7 +2476,6 @@ nsHTMLEditRules::InsertContainerAbove(nsIDOMNode *inNode, nsresult nsHTMLEditRules::InsertTab(nsIDOMSelection *aSelection, PRBool *aCancel, - PlaceholderTxn **aTxn, nsString *outString) { nsCOMPtr parentNode; @@ -2271,7 +2539,6 @@ nsHTMLEditRules::InsertTab(nsIDOMSelection *aSelection, nsresult nsHTMLEditRules::InsertSpace(nsIDOMSelection *aSelection, PRBool *aCancel, - PlaceholderTxn **aTxn, nsString *outString) { nsCOMPtr parentNode; @@ -2351,10 +2618,6 @@ nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection, res = mEditor->SplitNodeDeep( aHeader, aNode, aOffset, &newOffset); if (NS_FAILED(res)) return res; -// revisit the below when we move to using divs as standard paragraphs. -// need to create an "empty" div in the fisrt case below, and need to -// use a div instead of a

in the second case below - // if the new (righthand) header node is empty, delete it PRBool isEmpty; res = IsEmptyBlock(aHeader, &isEmpty); @@ -2366,10 +2629,13 @@ nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection, res = aSelection->Collapse(headerParent,offset+1); return res; } - // else rewrap it in a paragraph + // else rewrap it in a mozdiv nsCOMPtr newBlock; - nsAutoString blockType("p"); - res = ReplaceContainer(aHeader,&newBlock,blockType); + res = ReplaceContainer(aHeader,&newBlock,"div"); + if (NS_FAILED(res)) return res; + // give it special moz attr + nsCOMPtr mozDivElem = do_QueryInterface(newBlock); + res = mEditor->SetAttribute(mozDivElem, "type", "_moz"); if (NS_FAILED(res)) return res; res = aSelection->Collapse(newBlock,0); return res; @@ -2685,10 +2951,11 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString // to breaks, and runs of spaces to nbsps. // xxx floppy moose - // if curNode is a p, header, address, or pre, replace + // if curNode is a mozdiv, p, header, address, or pre, replace // it with a new block of correct type. // xxx floppy moose: pre cant hold everything the others can - if ((curNodeTag == "pre") || + if (IsMozDiv(curNode) || + (curNodeTag == "pre") || (curNodeTag == "p") || (curNodeTag == "h1") || (curNodeTag == "h2") || @@ -2710,7 +2977,7 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString (curNodeTag == "ul") || (curNodeTag == "li") || (curNodeTag == "blockquote") || - (curNodeTag == "div")) + (curNodeTag == "div")) // div's other than mozdivs { curBlock = 0; // forget any previous block used for previous inline nodes // recursion time @@ -2769,24 +3036,14 @@ nsHTMLEditRules::IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst) *aOutIsFirst = PR_FALSE; // find first editable child and compare it to aNode - nsCOMPtr parent; + nsCOMPtr parent, firstChild; 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 = GetNextHTMLNode(child, &tmp); - if (NS_FAILED(res)) return res; - if (!tmp) return NS_ERROR_FAILURE; - child = tmp; - } + res = GetFirstEditableChild(parent, &firstChild); + if (NS_FAILED(res)) return res; - *aOutIsFirst = (child.get() == aNode); + *aOutIsFirst = (firstChild.get() == aNode); return res; } @@ -2801,24 +3058,70 @@ nsHTMLEditRules::IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast) *aOutIsLast = PR_FALSE; // find last editable child and compare it to aNode - nsCOMPtr parent; + nsCOMPtr parent, lastChild; 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; + res = GetLastEditableChild(parent, &lastChild); + if (NS_FAILED(res)) return res; + + *aOutIsLast = (lastChild.get() == aNode); + return res; +} - if (!mEditor->IsEditable(child)) + +nsresult +nsHTMLEditRules::GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr *aOutFirstChild) +{ + // check parms + if (!aOutFirstChild || !aNode) return NS_ERROR_NULL_POINTER; + + // init out parms + *aOutFirstChild = nsnull; + + // find first editable child + nsCOMPtr child; + nsresult res = aNode->GetFirstChild(getter_AddRefs(child)); + if (NS_FAILED(res)) return res; + + while (child && !mEditor->IsEditable(child)) { nsCOMPtr tmp; - res = GetPriorHTMLNode(child, &tmp); + res = child->GetNextSibling(getter_AddRefs(tmp)); if (NS_FAILED(res)) return res; if (!tmp) return NS_ERROR_FAILURE; child = tmp; } - *aOutIsLast = (child.get() == aNode); + *aOutFirstChild = child; + return res; +} + + +nsresult +nsHTMLEditRules::GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr *aOutLastChild) +{ + // check parms + if (!aOutLastChild || !aNode) return NS_ERROR_NULL_POINTER; + + // init out parms + *aOutLastChild = nsnull; + + // find last editable child + nsCOMPtr child; + nsresult res = aNode->GetLastChild(getter_AddRefs(child)); + if (NS_FAILED(res)) return res; + + while (child && !mEditor->IsEditable(child)) + { + nsCOMPtr tmp; + res = child->GetPreviousSibling(getter_AddRefs(tmp)); + if (NS_FAILED(res)) return res; + if (!tmp) return NS_ERROR_FAILURE; + child = tmp; + } + + *aOutLastChild = child; return res; } @@ -2843,10 +3146,21 @@ nsHTMLEditRules::JoinNodesSmart( nsIDOMNode *aNodeLeft, nsresult res = NS_OK; // caller responsible for: // left & right node are same type - // left & right node have same parent - - nsCOMPtr parent; - aNodeLeft->GetParentNode(getter_AddRefs(parent)); + PRInt32 parOffset; + nsCOMPtr parent, rightParent; + res = nsEditor::GetNodeLocation(aNodeLeft, &parent, &parOffset); + if (NS_FAILED(res)) return res; + aNodeRight->GetParentNode(getter_AddRefs(rightParent)); + + // if they don't have the same parent, first move the 'right' node + // to after the 'left' one + if (parent != rightParent) + { + res = mEditor->DeleteNode(aNodeRight); + if (NS_FAILED(res)) return res; + res = mEditor->InsertNode(aNodeRight, parent, parOffset); + if (NS_FAILED(res)) return res; + } // defaults for outParams *aOutMergeParent = aNodeRight; @@ -2891,14 +3205,23 @@ nsHTMLEditRules::JoinNodesSmart( nsIDOMNode *aNodeLeft, } else { + // remember the last left child, and firt right child + nsCOMPtr lastLeft, firstRight; + res = GetLastEditableChild(aNodeLeft, &lastLeft); + if (NS_FAILED(res)) return res; + res = GetFirstEditableChild(aNodeRight, &firstRight); + if (NS_FAILED(res)) return res; + // for list items, divs, etc, merge smart res = mEditor->JoinNodes(aNodeLeft, aNodeRight, parent); if (NS_FAILED(res)) return res; - // XXX floppy moose - figure out newNodeLeft & newNodeRight and recurse - // res = JoinNodesSmart(newNodeLeft, newNodeRight, aOutMergeParent, aOutMergeOffset); - // if (NS_FAILED(res)) return res; - return res; + + if (lastLeft && firstRight && mEditor->NodesSameType(lastLeft, firstRight)) + { + return JoinNodesSmart(lastLeft, firstRight, aOutMergeParent, aOutMergeOffset); + } } + return res; } @@ -3057,10 +3380,17 @@ nsHTMLEditRules::PopListItem(nsIDOMNode *aListItem, PRBool *aOutOfList) res = mEditor->InsertNode(curNode, curParPar, parOffset); if (NS_FAILED(res)) return res; - // remove list items container if we promoted them out of list + // change list items container to mozdiv if we promoted them out of list if (!IsList(curParPar) && IsListItem(curNode)) { - res = RemoveContainer(curNode); + nsCOMPtr mozDiv; + res = ReplaceContainer(curNode, &mozDiv, "div"); + if (NS_FAILED(res)) return res; + // give it special moz attr + nsCOMPtr mozDivElem = do_QueryInterface(mozDiv); + res = mEditor->SetAttribute(mozDivElem, "type", "_moz"); + if (NS_FAILED(res)) return res; + *aOutOfList = PR_TRUE; if (NS_FAILED(res)) return res; } diff --git a/editor/base/nsHTMLEditRules.h b/editor/base/nsHTMLEditRules.h index c2583c5ea8b..addb5cca447 100644 --- a/editor/base/nsHTMLEditRules.h +++ b/editor/base/nsHTMLEditRules.h @@ -49,7 +49,6 @@ protected: // nsHTMLEditRules implementation methods nsresult WillInsertText(nsIDOMSelection *aSelection, PRBool *aCancel, - PlaceholderTxn **aTxn, const nsString *inString, nsString *outString, TypeInState typeInState, @@ -63,8 +62,8 @@ protected: nsresult WillAlign(nsIDOMSelection *aSelection, const nsString *alignType, PRBool *aCancel); nsresult WillMakeBasicBlock(nsIDOMSelection *aSelection, const nsString *aBlockType, PRBool *aCancel); - nsresult InsertTab(nsIDOMSelection *aSelection, PRBool *aCancel, PlaceholderTxn **aTxn, nsString *outString); - nsresult InsertSpace(nsIDOMSelection *aSelection, PRBool *aCancel, PlaceholderTxn **aTxn, nsString *outString); + nsresult InsertTab(nsIDOMSelection *aSelection, PRBool *aCancel, nsString *outString); + nsresult InsertSpace(nsIDOMSelection *aSelection, PRBool *aCancel, nsString *outString); nsresult ReturnInHeader(nsIDOMSelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset); nsresult ReturnInParagraph(nsIDOMSelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset, PRBool *aCancel); @@ -83,8 +82,12 @@ protected: static PRBool IsBreak(nsIDOMNode *aNode); static PRBool IsBody(nsIDOMNode *aNode); static PRBool IsBlockquote(nsIDOMNode *aNode); + static PRBool IsAnchor(nsIDOMNode *aNode); static PRBool IsDiv(nsIDOMNode *aNode); + static PRBool IsNormalDiv(nsIDOMNode *aNode); + static PRBool IsMozDiv(nsIDOMNode *aNode); static PRBool IsMailCite(nsIDOMNode *aNode); + static PRBool HasMozAttr(nsIDOMNode *aNode); static PRBool InBody(nsIDOMNode *aNode); @@ -92,6 +95,9 @@ protected: nsresult IsEmptyNode(nsIDOMNode *aNode, PRBool *outIsEmptyNode); PRBool IsFirstNode(nsIDOMNode *aNode); PRBool IsLastNode(nsIDOMNode *aNode); + PRBool AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock); + PRBool AtEndOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock); + nsresult CreateMozDiv(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr *outDiv); nsresult GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr *outNode); nsresult GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr *outNode); nsresult GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr *outNode); @@ -115,10 +121,12 @@ protected: nsresult ReplaceContainer(nsIDOMNode *inNode, nsCOMPtr *outNode, const nsString &aNodeType); nsresult RemoveContainer(nsIDOMNode *inNode); - nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr *outNode, nsString &aNodeType); + nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr *outNode, const nsString &aNodeType); nsresult IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst); nsresult IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast); + nsresult GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr *aOutFirstChild); + nsresult GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr *aOutLastChild); nsresult JoinNodesSmart( nsIDOMNode *aNodeLeft, nsIDOMNode *aNodeRight, diff --git a/editor/base/nsHTMLEditor.cpp b/editor/base/nsHTMLEditor.cpp index c4eaf618c17..2012a09a449 100644 --- a/editor/base/nsHTMLEditor.cpp +++ b/editor/base/nsHTMLEditor.cpp @@ -64,6 +64,7 @@ #include "nsAOLCiter.h" #include "nsInternetCiter.h" #include "nsISupportsPrimitives.h" +#include "InsertTextTxn.h" // netwerk #include "nsIURI.h" @@ -89,7 +90,7 @@ const unsigned char nbsp = 160; // {a6cf9107-15b3-11d2-932e-00805f8add32} #define NS_CNAVDTD_CID \ { 0xa6cf9107, 0x15b3, 0x11d2, { 0x93, 0x2e, 0x0, 0x80, 0x5f, 0x8a, 0xdd, 0x32 } } -static NS_DEFINE_CID(kCNavDTDCID, NS_CNAVDTD_CID); +static NS_DEFINE_CID(kCNavDTDCID, NS_CNAVDTD_CID); static NS_DEFINE_CID(kHTMLEditorCID, NS_HTMLEDITOR_CID); static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID); @@ -111,6 +112,8 @@ static const PRBool gNoisy = PR_FALSE; static char hrefText[] = "href"; static char anchorTxt[] = "anchor"; static char namedanchorText[] = "namedanchor"; +nsIAtom *nsHTMLEditor::gTypingTxnName; + #define IsLink(s) (s.EqualsIgnoreCase(hrefText)) #define IsNamedAnchor(s) (s.EqualsIgnoreCase(anchorTxt) || s.EqualsIgnoreCase(namedanchorText)) @@ -206,6 +209,8 @@ nsHTMLEditor::nsHTMLEditor() { // Done in nsEditor // NS_INIT_REFCNT(); + if (!gTypingTxnName) + gTypingTxnName = NS_NewAtom("Typing"); } nsHTMLEditor::~nsHTMLEditor() @@ -214,7 +219,7 @@ nsHTMLEditor::~nsHTMLEditor() //but we need to also remove the listeners or we have a leak nsCOMPtrselection; nsresult result = GetSelection(getter_AddRefs(selection)); - // if we don't get the selection, just skip this + // if we don't get the selection, just skip this if (NS_SUCCEEDED(result) && selection) { nsCOMPtrlistener; @@ -240,16 +245,16 @@ nsHTMLEditor::~nsHTMLEditor() if (mMouseListenerP) { erP->RemoveEventListenerByIID(mMouseListenerP, nsIDOMMouseListener::GetIID()); } - if (mTextListenerP) { + if (mTextListenerP) { erP->RemoveEventListenerByIID(mTextListenerP, nsIDOMTextListener::GetIID()); - } - if (mCompositionListenerP) { - erP->RemoveEventListenerByIID(mCompositionListenerP, nsIDOMCompositionListener::GetIID()); - } + } + if (mCompositionListenerP) { + erP->RemoveEventListenerByIID(mCompositionListenerP, nsIDOMCompositionListener::GetIID()); + } if (mFocusListenerP) { erP->RemoveEventListenerByIID(mFocusListenerP, nsIDOMFocusListener::GetIID()); } - if (mDragListenerP) { + if (mDragListenerP) { erP->RemoveEventListenerByIID(mDragListenerP, nsIDOMDragListener::GetIID()); } } @@ -305,7 +310,7 @@ NS_IMETHODIMP nsHTMLEditor::Init(nsIDOMDocument *aDoc, { NS_PRECONDITION(aDoc && aPresShell, "bad arg"); if (!aDoc || !aPresShell) - return NS_ERROR_NULL_POINTER; + return NS_ERROR_NULL_POINTER; nsresult result = NS_ERROR_NULL_POINTER; // Init the base editor @@ -333,7 +338,7 @@ NS_IMETHODIMP nsHTMLEditor::Init(nsIDOMDocument *aDoc, // XXX: ERROR CHECKING should InitRules return an error, and then we could check it here? InitRules(); - EnableUndo(PR_TRUE); + EnableUndo(PR_TRUE); // Set up a DTD XXX XXX // HACK: This should have happened in a document specific way @@ -382,8 +387,8 @@ nsHTMLEditor::InstallEventListeners() #ifdef DEBUG_TAGUE printf("nsTextEditor.cpp: failed to get TextEvent Listener\n"); #endif - HandleEventListenerError(); - return result; + HandleEventListenerError(); + return result; } // get a composition listener @@ -392,8 +397,8 @@ printf("nsTextEditor.cpp: failed to get TextEvent Listener\n"); #ifdef DEBUG_TAGUE printf("nsTextEditor.cpp: failed to get TextEvent Listener\n"); #endif - HandleEventListenerError(); - return result; + HandleEventListenerError(); + return result; } // get a drag listener @@ -423,31 +428,31 @@ printf("nsTextEditor.cpp: failed to get TextEvent Listener\n"); // register the event listeners with the DOM event reveiver result = erP->AddEventListenerByIID(mKeyListenerP, nsIDOMKeyListener::GetIID()); NS_ASSERTION(NS_SUCCEEDED(result), "failed to register key listener"); - if (NS_SUCCEEDED(result)) - { - result = erP->AddEventListenerByIID(mMouseListenerP, nsIDOMMouseListener::GetIID()); - NS_ASSERTION(NS_SUCCEEDED(result), "failed to register mouse listener"); - if (NS_SUCCEEDED(result)) - { - result = erP->AddEventListenerByIID(mFocusListenerP, nsIDOMFocusListener::GetIID()); - NS_ASSERTION(NS_SUCCEEDED(result), "failed to register focus listener"); - if (NS_SUCCEEDED(result)) - { - result = erP->AddEventListenerByIID(mTextListenerP, nsIDOMTextListener::GetIID()); - NS_ASSERTION(NS_SUCCEEDED(result), "failed to register text listener"); - if (NS_SUCCEEDED(result)) - { - result = erP->AddEventListenerByIID(mCompositionListenerP, nsIDOMCompositionListener::GetIID()); - NS_ASSERTION(NS_SUCCEEDED(result), "failed to register composition listener"); - if (NS_SUCCEEDED(result)) - { - result = erP->AddEventListenerByIID(mDragListenerP, nsIDOMDragListener::GetIID()); - NS_ASSERTION(NS_SUCCEEDED(result), "failed to register drag listener"); - } - } - } - } - } + if (NS_SUCCEEDED(result)) + { + result = erP->AddEventListenerByIID(mMouseListenerP, nsIDOMMouseListener::GetIID()); + NS_ASSERTION(NS_SUCCEEDED(result), "failed to register mouse listener"); + if (NS_SUCCEEDED(result)) + { + result = erP->AddEventListenerByIID(mFocusListenerP, nsIDOMFocusListener::GetIID()); + NS_ASSERTION(NS_SUCCEEDED(result), "failed to register focus listener"); + if (NS_SUCCEEDED(result)) + { + result = erP->AddEventListenerByIID(mTextListenerP, nsIDOMTextListener::GetIID()); + NS_ASSERTION(NS_SUCCEEDED(result), "failed to register text listener"); + if (NS_SUCCEEDED(result)) + { + result = erP->AddEventListenerByIID(mCompositionListenerP, nsIDOMCompositionListener::GetIID()); + NS_ASSERTION(NS_SUCCEEDED(result), "failed to register composition listener"); + if (NS_SUCCEEDED(result)) + { + result = erP->AddEventListenerByIID(mDragListenerP, nsIDOMDragListener::GetIID()); + NS_ASSERTION(NS_SUCCEEDED(result), "failed to register drag listener"); + } + } + } + } + } if (NS_FAILED(result)) { HandleEventListenerError(); } @@ -475,9 +480,9 @@ void nsHTMLEditor::InitRules() // instantiate the rules for this text editor // XXX: we should be told which set of rules to instantiate if (mFlags & eEditorPlaintextMask) - mRules = new nsTextEditRules(); - else - mRules = new nsHTMLEditRules(); + mRules = new nsTextEditRules(); + else + mRules = new nsHTMLEditRules(); mRules->Init(this, mFlags); } @@ -493,6 +498,8 @@ NS_IMETHODIMP nsHTMLEditor::EditorKeyPress(nsIDOMUIEvent* aKeyEvent) PRUint32 keyCode, character; PRBool isShift, ctrlKey, altKey, metaKey; nsresult res; + + nsAutoPlaceHolderBatch batch(this, gTypingTxnName); if (!aKeyEvent) return NS_ERROR_NULL_POINTER; @@ -518,7 +525,10 @@ NS_IMETHODIMP nsHTMLEditor::EditorKeyPress(nsIDOMUIEvent* aKeyEvent) else if (keyCode == nsIDOMUIEvent::DOM_VK_RETURN) { if (isShift && !(mFlags&eEditorPlaintextBit)) - return InsertBR(); // only inserts a br node + { + nsCOMPtr brNode; + return InsertBR(&brNode); // only inserts a br node + } else return InsertBreak(); // uses rules to figure out what to insert } @@ -595,11 +605,13 @@ NS_IMETHODIMP nsHTMLEditor::TabInTable(PRBool inIsShift, PRBool *outHandled) return NS_OK; } -NS_IMETHODIMP nsHTMLEditor::InsertBR() +NS_IMETHODIMP nsHTMLEditor::InsertBR(nsCOMPtr *outBRNode) { PRBool bCollapsed; nsCOMPtr selection; + if (!outBRNode) return NS_ERROR_NULL_POINTER; + *outBRNode = nsnull; nsresult res = GetSelection(getter_AddRefs(selection)); if (NS_FAILED(res)) return res; res = selection->GetIsCollapsed(&bCollapsed); @@ -640,6 +652,7 @@ NS_IMETHODIMP nsHTMLEditor::InsertBR() if (NS_FAILED(res)) return res; } + *outBRNode = brNode; return NS_OK; } @@ -650,6 +663,8 @@ NS_IMETHODIMP nsHTMLEditor::SetInlineProperty(nsIAtom *aProperty, if (!aProperty) { return NS_ERROR_NULL_POINTER; } if (!mRules) { return NS_ERROR_NOT_INITIALIZED; } + nsAutoEditBatch batchIt(this); + if (gNoisy) { nsAutoString propString; @@ -679,7 +694,6 @@ NS_IMETHODIMP nsHTMLEditor::SetInlineProperty(nsIAtom *aProperty, else { // set the text property for all selected ranges - nsEditor::BeginTransaction(); nsCOMPtr enumerator; result = selection->GetEnumerator(getter_AddRefs(enumerator)); if (NS_FAILED(result)) return result; @@ -761,7 +775,6 @@ NS_IMETHODIMP nsHTMLEditor::SetInlineProperty(nsIAtom *aProperty, // XXX: I'm blocked here because nsIDOMSelection doesn't provide a mechanism // for setting a compound selection yet. } - nsEditor::EndTransaction(); } // post-process result = mRules->DidDoAction(selection, &ruleInfo, result); @@ -816,7 +829,7 @@ NS_IMETHODIMP nsHTMLEditor::GetInlineProperty(nsIAtom *aProperty, nsCOMPtr currentItem; result = enumerator->CurrentItem(getter_AddRefs(currentItem)); // XXX: should be a while loop, to get each separate range - // XXX: ERROR_HANDLING can currentItem be null? + // XXX: ERROR_HANDLING can currentItem be null? if ((NS_SUCCEEDED(result)) && currentItem) { PRBool firstNodeInRange = PR_TRUE; // for each range, set a flag @@ -904,6 +917,8 @@ NS_IMETHODIMP nsHTMLEditor::RemoveInlineProperty(nsIAtom *aProperty, const nsStr if (!aProperty) { return NS_ERROR_NULL_POINTER; } if (!mRules) { return NS_ERROR_NOT_INITIALIZED; } + nsAutoEditBatch batchIt(this); + if (gNoisy) { nsAutoString propString; @@ -941,7 +956,6 @@ NS_IMETHODIMP nsHTMLEditor::RemoveInlineProperty(nsIAtom *aProperty, const nsStr PRInt32 rangeStartOffset, rangeEndOffset; GetTextSelectionOffsetsForRange(selection, getter_AddRefs(parentForSelection), rangeStartOffset, rangeEndOffset); - nsEditor::BeginTransaction(); nsCOMPtr startParent, endParent; PRInt32 startOffset, endOffset; nsCOMPtr enumerator; @@ -959,17 +973,17 @@ NS_IMETHODIMP nsHTMLEditor::RemoveInlineProperty(nsIAtom *aProperty, const nsStr nsCOMPtr range( do_QueryInterface(currentItem) ); nsCOMPtrcommonParent; result = range->GetCommonParent(getter_AddRefs(commonParent)); - if (NS_FAILED(result)) return result; - if (!commonParent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!commonParent) return NS_ERROR_NULL_POINTER; range->GetStartOffset(&startOffset); range->GetEndOffset(&endOffset); result = range->GetStartParent(getter_AddRefs(startParent)); - if (NS_FAILED(result)) return result; - if (!startParent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!startParent) return NS_ERROR_NULL_POINTER; result = range->GetEndParent(getter_AddRefs(endParent)); - if (NS_FAILED(result)) return result; - if (!endParent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!endParent) return NS_ERROR_NULL_POINTER; if (startParent.get()==endParent.get()) { // the range is entirely contained within a single text node @@ -996,14 +1010,13 @@ NS_IMETHODIMP nsHTMLEditor::RemoveInlineProperty(nsIAtom *aProperty, const nsStr // for setting a compound selection yet. } } - if (NS_SUCCEEDED(result)) - { - result = CollapseAdjacentTextNodes(selection); // we may have created wasteful consecutive text nodes. collapse them. - } - nsEditor::EndTransaction(); + if (NS_SUCCEEDED(result)) + { + result = CollapseAdjacentTextNodes(selection); // we may have created wasteful consecutive text nodes. collapse them. + } if (NS_SUCCEEDED(result)) { - // XXX: ERROR_HANDLING should get a result and validate it + // XXX: ERROR_HANDLING should get a result and validate it ResetTextSelectionForRange(parentForSelection, rangeStartOffset, rangeEndOffset, selection); } } @@ -1066,11 +1079,15 @@ NS_IMETHODIMP nsHTMLEditor::DeleteSelection(nsIEditor::ESelectionCollapseDirecti nsCOMPtr selection; PRBool cancel= PR_FALSE; - nsresult result = nsEditor::BeginTransaction(); - if (NS_FAILED(result)) { return result; } + // unnamed placeholder txns dont merge, but they do get sucked + // into placeholders that they are nested in. So this delte wont + // merge with other deletes, but if it happens in the course of + // a typing placehilder context, it will be consumed by that. + // This is the desired behavior. + nsAutoPlaceHolderBatch batch(this, nsnull); // pre-process - result = GetSelection(getter_AddRefs(selection)); + nsresult result = GetSelection(getter_AddRefs(selection)); if (NS_FAILED(result)) return result; if (!selection) return NS_ERROR_NULL_POINTER; @@ -1084,10 +1101,6 @@ NS_IMETHODIMP nsHTMLEditor::DeleteSelection(nsIEditor::ESelectionCollapseDirecti result = mRules->DidDoAction(selection, &ruleInfo, result); } - // XXX: ERROR_HANDLING is there any reason to not consider this a serious error? - nsresult endTxnResult = nsEditor::EndTransaction(); // don't return this result! - NS_ASSERTION ((NS_SUCCEEDED(endTxnResult)), "bad end transaction result"); - return result; } @@ -1105,7 +1118,7 @@ NS_IMETHODIMP nsHTMLEditor::InsertText(const nsString& aStringToInsert) nsAutoString resultString; PlaceholderTxn *placeholderTxn=nsnull; nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertText); - ruleInfo.placeTxn = &placeholderTxn; +// ruleInfo.placeTxn = &placeholderTxn; ruleInfo.inString = &aStringToInsert; ruleInfo.outString = &resultString; ruleInfo.typeInState = *mTypeInState; @@ -1118,8 +1131,8 @@ NS_IMETHODIMP nsHTMLEditor::InsertText(const nsString& aStringToInsert) // post-process result = mRules->DidDoAction(selection, &ruleInfo, result); } - if (placeholderTxn) - placeholderTxn->SetAbsorb(PR_FALSE); // this ends the merging of txns into placeholderTxn +// if (placeholderTxn) +// placeholderTxn->SetAbsorb(PR_FALSE); // this ends the merging of txns into placeholderTxn return result; } @@ -1219,8 +1232,6 @@ NS_IMETHODIMP nsHTMLEditor::InsertBreak() nsCOMPtr selection; PRBool cancel= PR_FALSE; - nsAutoEditBatch beginBatching(this); - // pre-process res = GetSelection(getter_AddRefs(selection)); if (NS_FAILED(res)) return res; @@ -1295,6 +1306,8 @@ nsHTMLEditor::InsertElement(nsIDOMElement* aElement, PRBool aDeleteSelection) if (!aElement) return NS_ERROR_NULL_POINTER; + nsAutoEditBatch beginBatching(this); + nsCOMPtrselection; res = GetSelection(getter_AddRefs(selection)); if (!NS_SUCCEEDED(res) || !selection) @@ -1307,8 +1320,6 @@ nsHTMLEditor::InsertElement(nsIDOMElement* aElement, PRBool aDeleteSelection) res = mRules->WillDoAction(selection, &ruleInfo, &cancel); if (cancel || (NS_FAILED(res))) return res; - nsAutoEditBatch beginBatching(this); - if (aDeleteSelection) { nsCOMPtr tempNode; @@ -1337,7 +1348,7 @@ nsHTMLEditor::InsertElement(nsIDOMElement* aElement, PRBool aDeleteSelection) nsCOMPtr parentSelectedNode; PRInt32 offsetForInsert; res = selection->GetAnchorNode(getter_AddRefs(parentSelectedNode)); - // XXX: ERROR_HANDLING bad XPCOM usage + // XXX: ERROR_HANDLING bad XPCOM usage if (NS_SUCCEEDED(res) && NS_SUCCEEDED(selection->GetAnchorOffset(&offsetForInsert)) && parentSelectedNode) { #ifdef DEBUG_cmanske @@ -1427,8 +1438,8 @@ nsHTMLEditor::DeleteSelectionAndCreateNode(const nsString& aTag, // we want the selection to be just after the new node nsCOMPtr selection; result = GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(result)) return result; - if (!selection) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!selection) return NS_ERROR_NULL_POINTER; result = selection->Collapse(parentSelectedNode, offsetOfNewNode+1); return result; @@ -1444,8 +1455,8 @@ nsHTMLEditor::SelectElement(nsIDOMElement* aElement) { nsCOMPtr selection; res = GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(res)) return res; - if (!selection) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!selection) return NS_ERROR_NULL_POINTER; nsCOMPtrparent; res = aElement->GetParentNode(getter_AddRefs(parent)); if (NS_SUCCEEDED(res) && parent) @@ -1457,10 +1468,10 @@ nsHTMLEditor::SelectElement(nsIDOMElement* aElement) { // Collapse selection to just before desired element, res = selection->Collapse(parent, offsetInParent); - if (NS_SUCCEEDED(res)) { - // then extend it to just after - res = selection->Extend(parent, offsetInParent+1); - } + if (NS_SUCCEEDED(res)) { + // then extend it to just after + res = selection->Extend(parent, offsetInParent+1); + } } } } @@ -1477,12 +1488,12 @@ nsHTMLEditor::SetCaretAfterElement(nsIDOMElement* aElement) { nsCOMPtr selection; res = GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(res)) return res; - if (!selection) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!selection) return NS_ERROR_NULL_POINTER; nsCOMPtrparent; res = aElement->GetParentNode(getter_AddRefs(parent)); - if (NS_FAILED(res)) return res; - if (!parent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!parent) return NS_ERROR_NULL_POINTER; PRInt32 offsetInParent; res = GetChildOffset(aElement, parent, offsetInParent); if (NS_SUCCEEDED(res)) @@ -1646,7 +1657,7 @@ nsHTMLEditor::AddBlockParent(nsString& aParentTag) enumerator->First(); nsCOMPtr currentItem; res = enumerator->CurrentItem(getter_AddRefs(currentItem)); - // XXX: ERROR_HANDLING can currentItem be null? + // XXX: ERROR_HANDLING can currentItem be null? if ((NS_SUCCEEDED(res)) && (currentItem)) { nsCOMPtr range( do_QueryInterface(currentItem) ); @@ -1692,7 +1703,7 @@ nsHTMLEditor::ReplaceBlockParent(nsString& aParentTag) enumerator->First(); nsCOMPtr currentItem; res = enumerator->CurrentItem(getter_AddRefs(currentItem)); - // XXX: ERROR_HANDLING can currentItem be null? + // XXX: ERROR_HANDLING can currentItem be null? if ((NS_SUCCEEDED(res)) && (currentItem)) { nsCOMPtr range( do_QueryInterface(currentItem) ); @@ -1729,7 +1740,7 @@ nsHTMLEditor::RemoveParagraphStyle() enumerator->First(); nsCOMPtr currentItem; res = enumerator->CurrentItem(getter_AddRefs(currentItem)); - // XXX: ERROR_HANDLING can currentItem be null? + // XXX: ERROR_HANDLING can currentItem be null? if ((NS_SUCCEEDED(res)) && (currentItem)) { nsCOMPtr range( do_QueryInterface(currentItem) ); @@ -1761,7 +1772,7 @@ nsHTMLEditor::RemoveParent(const nsString &aParentTag) enumerator->First(); nsCOMPtr currentItem; res = enumerator->CurrentItem(getter_AddRefs(currentItem)); - // XXX: ERROR_HANDLING can currentItem be null? + // XXX: ERROR_HANDLING can currentItem be null? if ((NS_SUCCEEDED(res)) && (currentItem)) { nsCOMPtr range( do_QueryInterface(currentItem) ); @@ -2134,7 +2145,7 @@ NODE_FOUND: } // Search up the parent chain // We should never fail because of root test below, but lets be safe - // XXX: ERROR_HANDLING error return code lost + // XXX: ERROR_HANDLING error return code lost if (!NS_SUCCEEDED(currentNode->GetParentNode(getter_AddRefs(parent))) || !parent) break; @@ -2198,14 +2209,14 @@ nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aRetu // included a collapsed selection (just a caret in a link) nsCOMPtr anchorNode; res = selection->GetAnchorNode(getter_AddRefs(anchorNode)); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; PRInt32 anchorOffset = -1; if (anchorNode) selection->GetAnchorOffset(&anchorOffset); nsCOMPtr focusNode; res = selection->GetFocusNode(getter_AddRefs(focusNode)); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; PRInt32 focusOffset = -1; if (focusNode) selection->GetFocusOffset(&focusOffset); @@ -2228,7 +2239,7 @@ nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aRetu #endif nsCOMPtr parentLinkOfAnchor; res = GetElementOrParentByTagName("href", anchorNode, getter_AddRefs(parentLinkOfAnchor)); - // XXX: ERROR_HANDLING can parentLinkOfAnchor be null? + // XXX: ERROR_HANDLING can parentLinkOfAnchor be null? if (NS_SUCCEEDED(res) && parentLinkOfAnchor) { if (isCollapsed) @@ -2268,7 +2279,7 @@ nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aRetu { nsCOMPtr enumerator; res = selection->GetEnumerator(getter_AddRefs(enumerator)); - // XXX: ERROR_HANDLING unclear what to do here, should an error just be returned if enumerator is null or res failed? + // XXX: ERROR_HANDLING unclear what to do here, should an error just be returned if enumerator is null or res failed? if (NS_SUCCEEDED(res) && enumerator) { enumerator->First(); @@ -2281,7 +2292,7 @@ nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aRetu res = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull, nsIContentIterator::GetIID(), getter_AddRefs(iter)); - // XXX: ERROR_HANDLING XPCOM usage + // XXX: ERROR_HANDLING XPCOM usage if ((NS_SUCCEEDED(res)) && iter) { iter->Init(range); @@ -2423,8 +2434,8 @@ nsHTMLEditor::CreateElementWithDefaults(const nsString& aTagName, nsIDOMElement* space += nbsp; // If we fail here, we return NS_OK anyway, since we have an OK cell node nsresult result = doc->CreateTextNode(space, getter_AddRefs(newTextNode)); - if (NS_FAILED(result)) return result; - if (!newTextNode) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!newTextNode) return NS_ERROR_NULL_POINTER; nsCOMPtrresultNode; result = newCellNode->AppendChild(newTextNode, getter_AddRefs(resultNode)); @@ -2448,7 +2459,7 @@ nsHTMLEditor::InsertLinkAroundSelection(nsIDOMElement* aAnchorElement) // DON'T RETURN EXCEPT AT THE END -- WE NEED TO RELEASE THE aAnchorElement if (!aAnchorElement) - goto DELETE_ANCHOR; // DON'T USE GOTO IN C++! + goto DELETE_ANCHOR; // DON'T USE GOTO IN C++! // We must have a real selection res = GetSelection(getter_AddRefs(selection)); @@ -2474,7 +2485,7 @@ nsHTMLEditor::InsertLinkAroundSelection(nsIDOMElement* aAnchorElement) if (anchor) { nsAutoString href; - // XXX: ERROR_HANDLING return code lost + // XXX: ERROR_HANDLING return code lost if (NS_SUCCEEDED(anchor->GetHref(href)) && href.GetUnicode() && href.Length() > 0) { nsAutoEditBatch beginBatching(this); @@ -2671,38 +2682,38 @@ NS_IMETHODIMP nsHTMLEditor::GetMaxTextLength(PRInt32& aMaxTextLength) NS_IMETHODIMP nsHTMLEditor::AddStyleSheet(nsICSSStyleSheet* aSheet) { - AddStyleSheetTxn* txn; - nsresult rv = CreateTxnForAddStyleSheet(aSheet, &txn); + AddStyleSheetTxn* txn; + nsresult rv = CreateTxnForAddStyleSheet(aSheet, &txn); if (!txn) rv = NS_ERROR_NULL_POINTER; - if (NS_SUCCEEDED(rv)) - { - rv = Do(txn); - if (NS_SUCCEEDED(rv)) - { - mLastStyleSheet = do_QueryInterface(aSheet); // save it so we can remove before applying the next one - } - } - - return rv; + if (NS_SUCCEEDED(rv)) + { + rv = Do(txn); + if (NS_SUCCEEDED(rv)) + { + mLastStyleSheet = do_QueryInterface(aSheet); // save it so we can remove before applying the next one + } + } + + return rv; } NS_IMETHODIMP nsHTMLEditor::RemoveStyleSheet(nsICSSStyleSheet* aSheet) { - RemoveStyleSheetTxn* txn; - nsresult rv = CreateTxnForRemoveStyleSheet(aSheet, &txn); + RemoveStyleSheetTxn* txn; + nsresult rv = CreateTxnForRemoveStyleSheet(aSheet, &txn); if (!txn) rv = NS_ERROR_NULL_POINTER; - if (NS_SUCCEEDED(rv)) - { - rv = Do(txn); - if (NS_SUCCEEDED(rv)) - { - mLastStyleSheet = nsnull; // forget it - } - } - - return rv; + if (NS_SUCCEEDED(rv)) + { + rv = Do(txn); + if (NS_SUCCEEDED(rv)) + { + mLastStyleSheet = nsnull; // forget it + } + } + + return rv; } @@ -3406,7 +3417,7 @@ NS_IMETHODIMP nsHTMLEditor::OutputToString(nsString& aOutputString, if (NS_SUCCEEDED(rv) && selection) encoder->SetSelection(selection); } - + // Set the wrap column. If our wrap column is 0, // i.e. wrap to body width, then don't set it, let the // document encoder use its own default. @@ -3492,7 +3503,7 @@ NS_IMETHODIMP nsHTMLEditor::OutputToStream(nsIOutputStream* aOutputStream, if (NS_SUCCEEDED(rv) && selection) encoder->SetSelection(selection); } - + // Set the wrap column. If our wrap column is 0, // i.e. wrap to body width, then don't set it, let the // document encoder use its own default. @@ -3522,10 +3533,10 @@ nsHTMLEditor::DebugUnitTests(PRInt32 *outNumTests, PRInt32 *outNumTestsFailed) if (!outNumTests || !outNumTestsFailed) return NS_ERROR_NULL_POINTER; - TextEditorTest *tester = new TextEditorTest(); - if (!tester) - return NS_ERROR_OUT_OF_MEMORY; - + TextEditorTest *tester = new TextEditorTest(); + if (!tester) + return NS_ERROR_OUT_OF_MEMORY; + tester->Run(this, outNumTests, outNumTestsFailed); delete tester; return NS_OK; @@ -3579,7 +3590,7 @@ nsHTMLEditor::ReplaceStyleSheet(nsICSSStyleSheet *aNewSheet) { nsresult rv = NS_OK; - BeginTransaction(); + nsAutoEditBatch batchIt(this); if (mLastStyleSheet) { @@ -3589,8 +3600,6 @@ nsHTMLEditor::ReplaceStyleSheet(nsICSSStyleSheet *aNewSheet) rv = AddStyleSheet(aNewSheet); - EndTransaction(); - return rv; } @@ -3721,7 +3730,7 @@ void nsHTMLEditor::IsTextPropertySetByContent(nsIDOMNode *aNode, aProperty->ToString(propName); nsCOMPtrparent; result = aNode->GetParentNode(getter_AddRefs(parent)); - if (NS_FAILED(result)) return; + if (NS_FAILED(result)) return; while (parent) { nsCOMPtrelement; @@ -3796,7 +3805,7 @@ nsresult nsHTMLEditor::GetTextSelectionOffsets(nsIDOMSelection *aSelection, PRInt32 &aOutStartOffset, PRInt32 &aOutEndOffset) { - if(!aSelection) { return NS_ERROR_NULL_POINTER; } + if(!aSelection) { return NS_ERROR_NULL_POINTER; } nsresult result; // initialize out params aOutStartOffset = 0; // default to first char in selection @@ -3811,8 +3820,8 @@ nsresult nsHTMLEditor::GetTextSelectionOffsets(nsIDOMSelection *aSelection, nsCOMPtr enumerator; result = aSelection->GetEnumerator(getter_AddRefs(enumerator)); - if (NS_FAILED(result)) return result; - if (!enumerator) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!enumerator) return NS_ERROR_NULL_POINTER; // don't use "result" in this block enumerator->First(); @@ -3845,7 +3854,7 @@ nsresult nsHTMLEditor::GetAbsoluteOffsetsForPoints(nsIDOMNode *aInStartNode, PRInt32 &aOutStartOffset, PRInt32 &aOutEndOffset) { - if(!aInStartNode || !aInEndNode || !aInCommonParentNode) { return NS_ERROR_NULL_POINTER; } + if(!aInStartNode || !aInEndNode || !aInCommonParentNode) { return NS_ERROR_NULL_POINTER; } nsresult result; // initialize out params @@ -3915,8 +3924,8 @@ nsHTMLEditor::GetTextSelectionOffsetsForRange(nsIDOMSelection *aSelection, PRInt32 &aOutStartOffset, PRInt32 &aEndOffset) { - if (!aSelection) { return NS_ERROR_NULL_POINTER; } - aOutStartOffset = aEndOffset = 0; + if (!aSelection) { return NS_ERROR_NULL_POINTER; } + aOutStartOffset = aEndOffset = 0; nsresult result; nsCOMPtr startNode, endNode; @@ -3928,8 +3937,8 @@ nsHTMLEditor::GetTextSelectionOffsetsForRange(nsIDOMSelection *aSelection, nsCOMPtr enumerator; result = aSelection->GetEnumerator(getter_AddRefs(enumerator)); - if (NS_FAILED(result)) return result; - if (!enumerator) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!enumerator) return NS_ERROR_NULL_POINTER; enumerator->First(); nsCOMPtr currentItem; result = enumerator->CurrentItem(getter_AddRefs(currentItem)); @@ -3943,8 +3952,8 @@ nsHTMLEditor::GetTextSelectionOffsetsForRange(nsIDOMSelection *aSelection, 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; @@ -3975,7 +3984,7 @@ nsHTMLEditor::GetTextSelectionOffsetsForRange(nsIDOMSelection *aSelection, iter->Next(); iter->CurrentNode(getter_AddRefs(content)); } - return result; + return result; } void nsHTMLEditor::ResetTextSelectionForRange(nsIDOMNode *aParent, @@ -3983,7 +3992,7 @@ void nsHTMLEditor::ResetTextSelectionForRange(nsIDOMNode *aParent, PRInt32 aEndOffset, nsIDOMSelection *aSelection) { - if (!aParent || !aSelection) { return; } // XXX: should return an error + if (!aParent || !aSelection) { return; } // XXX: should return an error nsCOMPtr startNode, endNode; PRInt32 startOffset, endOffset; @@ -3992,8 +4001,8 @@ void nsHTMLEditor::ResetTextSelectionForRange(nsIDOMNode *aParent, result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull, nsIContentIterator::GetIID(), getter_AddRefs(iter)); - if (NS_FAILED(result)) return; - if (!iter) return; + if (NS_FAILED(result)) return; + if (!iter) return; PRBool setStart = PR_FALSE; PRUint32 totalLength=0; nsCOMPtrtextNode; @@ -4025,7 +4034,7 @@ void nsHTMLEditor::ResetTextSelectionForRange(nsIDOMNode *aParent, } iter->Next(); iter->CurrentNode(getter_AddRefs(content)); - } + } aSelection->Collapse(startNode, startOffset); aSelection->Extend(endNode, endOffset); } @@ -4123,7 +4132,7 @@ nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode, if (((eReplaceParent==aTransformation) && (PR_FALSE==parentTag.EqualsIgnoreCase(aParentTag))) || (eInsertParent==aTransformation)) { - if (gNoisy) { DebugDumpContent(); } // DEBUG + if (gNoisy) { DebugDumpContent(); } // DEBUG res = ReParentBlockContent(nodeToReParent, aParentTag, blockParentNode, parentTag, aTransformation, getter_AddRefs(newParentNode)); if ((NS_SUCCEEDED(res)) && (newParentNode) && (eReplaceParent==aTransformation)) @@ -4165,7 +4174,7 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, PRBool removeBreakAfter = PR_FALSE; nsCOMPtrancestor; nsresult res = aNode->GetParentNode(getter_AddRefs(ancestor)); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; nsCOMPtrpreviousAncestor = do_QueryInterface(aNode); while (ancestor) { @@ -4178,15 +4187,15 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, } previousAncestor = do_QueryInterface(ancestor); res = ancestorElement->GetParentNode(getter_AddRefs(ancestor)); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; } // now, previousAncestor is the node we are operating on nsCOMPtrleftNode, rightNode; res = GetBlockSection(previousAncestor, getter_AddRefs(leftNode), getter_AddRefs(rightNode)); - if (NS_FAILED(res)) return res; - if (!leftNode || !rightNode) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!leftNode || !rightNode) return NS_ERROR_NULL_POINTER; // determine some state for managing
s around the new block PRBool isSubordinateBlock = PR_FALSE; // if true, the content is already in a subordinate block @@ -4219,8 +4228,8 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, { nsCOMPtr grandParent; res = blockParentNode->GetParentNode(getter_AddRefs(grandParent)); - if (NS_FAILED(res)) return res; - if (!grandParent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!grandParent) return NS_ERROR_NULL_POINTER; nsCOMPtrfirstChildNode, lastChildNode; blockParentNode->GetFirstChild(getter_AddRefs(firstChildNode)); blockParentNode->GetLastChild(getter_AddRefs(lastChildNode)); @@ -4364,13 +4373,13 @@ nsHTMLEditor::ReParentContentOfRange(nsIDOMRange *aRange, nsresult res; nsISupportsArray *blockSections; res = NS_NewISupportsArray(&blockSections); - if (NS_FAILED(res)) return res; - if (!blockSections) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!blockSections) return NS_ERROR_NULL_POINTER; res = GetBlockSectionsForRange(aRange, blockSections); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; - // no embedded returns allowed below here in this method, or you'll get a space leak + // no embedded returns allowed below here in this method, or you'll get a space leak nsIDOMRange *subRange; subRange = (nsIDOMRange *)(blockSections->ElementAt(0)); while (subRange) @@ -4383,10 +4392,10 @@ nsHTMLEditor::ReParentContentOfRange(nsIDOMRange *aRange, res = ReParentContentOfNode(startParent, aParentTag, aTranformation); } NS_RELEASE(subRange); - if (NS_FAILED(res)) - { // be sure to break after free of subRange - break; - } + if (NS_FAILED(res)) + { // be sure to break after free of subRange + break; + } blockSections->RemoveElementAt(0); subRange = (nsIDOMRange *)(blockSections->ElementAt(0)); } @@ -4404,21 +4413,21 @@ nsHTMLEditor::RemoveParagraphStyleFromRange(nsIDOMRange *aRange) nsISupportsArray *blockSections; res = NS_NewISupportsArray(&blockSections); if (NS_FAILED(res)) return res; - if (!blockSections) return NS_ERROR_NULL_POINTER; + if (!blockSections) return NS_ERROR_NULL_POINTER; res = GetBlockSectionsForRange(aRange, blockSections); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; - nsIDOMRange *subRange; + nsIDOMRange *subRange; subRange = (nsIDOMRange *)(blockSections->ElementAt(0)); while (subRange) { res = RemoveParagraphStyleFromBlockContent(subRange); NS_RELEASE(subRange); - if (NS_FAILED(res)) - { // be sure to break after subrange is released - break; - } + if (NS_FAILED(res)) + { // be sure to break after subrange is released + break; + } blockSections->RemoveElementAt(0); subRange = (nsIDOMRange *)(blockSections->ElementAt(0)); } @@ -4436,7 +4445,7 @@ nsHTMLEditor::RemoveParagraphStyleFromBlockContent(nsIDOMRange *aRange) aRange->GetStartParent(getter_AddRefs(startParent)); nsCOMPtrblockParentElement; res = GetBlockParent(startParent, getter_AddRefs(blockParentElement)); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; while (blockParentElement) { @@ -4456,8 +4465,8 @@ nsHTMLEditor::RemoveParagraphStyleFromBlockContent(nsIDOMRange *aRange) { nsCOMPtrgrandParent; blockParentElement->GetParentNode(getter_AddRefs(grandParent)); - if (NS_FAILED(res)) return res; - if (!grandParent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!grandParent) return NS_ERROR_NULL_POINTER; PRInt32 offsetInParent; res = GetChildOffset(blockParentElement, grandParent, offsetInParent); @@ -4472,21 +4481,21 @@ nsHTMLEditor::RemoveParagraphStyleFromBlockContent(nsIDOMRange *aRange) { res = DeleteNode(childNode); if (NS_SUCCEEDED(res)) - { + { res = InsertNode(childNode, grandParent, offsetInParent); - if (NS_FAILED(res)) return res; - } + if (NS_FAILED(res)) return res; + } } } if (NS_SUCCEEDED(res)) - { + { res = DeleteNode(blockParentElement); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; } } } res = GetBlockParent(startParent, getter_AddRefs(blockParentElement)); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; } return res; } @@ -4499,8 +4508,8 @@ nsHTMLEditor::RemoveParentFromRange(const nsString &aParentTag, nsIDOMRange *aRa nsresult res; nsISupportsArray *blockSections; res = NS_NewISupportsArray(&blockSections); - if (NS_FAILED(res)) return res; - if (!blockSections) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!blockSections) return NS_ERROR_NULL_POINTER; res = GetBlockSectionsForRange(aRange, blockSections); if (NS_SUCCEEDED(res)) { @@ -4510,10 +4519,10 @@ nsHTMLEditor::RemoveParentFromRange(const nsString &aParentTag, nsIDOMRange *aRa { res = RemoveParentFromBlockContent(aParentTag, subRange); NS_RELEASE(subRange); - if (NS_FAILED(res)) - { - break; - } + if (NS_FAILED(res)) + { + break; + } blockSections->RemoveElementAt(0); subRange = (nsIDOMRange *)(blockSections->ElementAt(0)); } @@ -4530,13 +4539,13 @@ nsHTMLEditor::RemoveParentFromBlockContent(const nsString &aParentTag, nsIDOMRan nsresult res; nsCOMPtrstartParent; res = aRange->GetStartParent(getter_AddRefs(startParent)); - if (NS_FAILED(res)) return res; - if (!startParent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!startParent) return NS_ERROR_NULL_POINTER; nsCOMPtrparentNode; nsCOMPtrparentElement; res = startParent->GetParentNode(getter_AddRefs(parentNode)); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; while (parentNode) { @@ -4550,8 +4559,8 @@ nsHTMLEditor::RemoveParentFromBlockContent(const nsString &aParentTag, nsIDOMRan // go through list backwards so deletes don't interfere with the iteration nsCOMPtr childNodes; res = parentElement->GetChildNodes(getter_AddRefs(childNodes)); - if (NS_FAILED(res)) return res; - if (!childNodes) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!childNodes) return NS_ERROR_NULL_POINTER; nsCOMPtrgrandParent; parentElement->GetParentNode(getter_AddRefs(grandParent)); @@ -4571,7 +4580,7 @@ nsHTMLEditor::RemoveParentFromBlockContent(const nsString &aParentTag, nsIDOMRan res = DeleteNode(childNode); if (NS_FAILED(res)) return res; res = InsertNode(childNode, grandParent, offsetInParent); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; } res = DeleteNode(parentElement); if (NS_FAILED(res)) { return res; } @@ -4582,7 +4591,7 @@ nsHTMLEditor::RemoveParentFromBlockContent(const nsString &aParentTag, nsIDOMRan break; } res = parentElement->GetParentNode(getter_AddRefs(parentNode)); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; } return res; } @@ -4595,8 +4604,8 @@ PRBool nsHTMLEditor::IsElementInBody(nsIDOMElement* aElement) { nsIDOMElement* bodyElement = nsnull; nsresult res = nsEditor::GetBodyElement(&bodyElement); - if (NS_FAILED(res)) return res; - if (!bodyElement) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!bodyElement) return NS_ERROR_NULL_POINTER; nsCOMPtr parent; nsCOMPtr currentElement = do_QueryInterface(aElement); if (currentElement) @@ -4825,8 +4834,8 @@ nsHTMLEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr &parent nsresult result=NS_ERROR_NOT_INITIALIZED; nsCOMPtr selection; result = GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(result)) return result; - if (!selection) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!selection) return NS_ERROR_NULL_POINTER; PRBool collapsed; result = selection->GetIsCollapsed(&collapsed); @@ -5058,8 +5067,8 @@ nsHTMLEditor::SetTextPropertiesForNode(nsIDOMNode *aNode, { nsCOMPtrnewStyleNode; result = nsEditor::CreateNode(tag, aParent, 0, getter_AddRefs(newStyleNode)); - if (NS_FAILED(result)) return result; - if (!newStyleNode) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!newStyleNode) return NS_ERROR_NULL_POINTER; nsCOMPtrnodeAsChar; nodeAsChar = do_QueryInterface(aNode); @@ -5201,8 +5210,8 @@ NS_IMETHODIMP nsHTMLEditor::MoveContentOfNodeIntoNewParent(nsIDOMNode *aNode, // set the selection nsCOMPtrselection; result = GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(result)) return result; - if (!selection) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!selection) return NS_ERROR_NULL_POINTER; selection->Collapse(newChildNode, 0); PRInt32 endOffset = aEndOffset-aStartOffset; selection->Extend(newChildNode, endOffset); @@ -5238,10 +5247,10 @@ nsHTMLEditor::SetTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode, IsTextPropertySetByContent(aStartNode, aPropName, aAttribute, aValue, textPropertySet, getter_AddRefs(resultNode)); if (PR_FALSE==textPropertySet) { - result = RemoveTextPropertiesForNodeWithDifferentParents(aStartNode, aStartOffset, - aEndNode, aEndOffset, - aParent, aPropName, aAttribute); - if (NS_FAILED(result)) return result; + result = RemoveTextPropertiesForNodeWithDifferentParents(aStartNode, aStartOffset, + aEndNode, aEndOffset, + aParent, aPropName, aAttribute); + if (NS_FAILED(result)) return result; nsAutoString tag; aPropName->ToString(tag); @@ -5249,16 +5258,16 @@ nsHTMLEditor::SetTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode, nsCOMPtrnewStyleNode; nsCOMPtrdoc; result = GetDocument(getter_AddRefs(doc)); - if (NS_FAILED(result)) return result; - if (!doc) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!doc) return NS_ERROR_NULL_POINTER; nsCOMPtrnewElement; result = doc->CreateElement(tag, getter_AddRefs(newElement)); - if (NS_FAILED(result)) return result; - if (!newElement) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!newElement) return NS_ERROR_NULL_POINTER; newStyleNode = do_QueryInterface(newElement); - if (!newStyleNode) return NS_ERROR_NULL_POINTER; + if (!newStyleNode) return NS_ERROR_NULL_POINTER; result = MoveContiguousContentIntoNewParent(aStartNode, aStartOffset, aEndNode, aEndOffset, aParent, newStyleNode); if (NS_SUCCEEDED(result) && aAttribute && 0!=aAttribute->Length()) { @@ -5271,7 +5280,7 @@ nsHTMLEditor::SetTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode, result = newStyleElement->SetAttribute(*aAttribute, value); } } - if (gNoisy) { printf("---------- end nsTextEditor::SetTextPropertiesForNodesWithSameParent ----------\n"); } + if (gNoisy) { printf("---------- end nsTextEditor::SetTextPropertiesForNodesWithSameParent ----------\n"); } return result; } @@ -5285,7 +5294,7 @@ nsHTMLEditor::MoveContiguousContentIntoNewParent(nsIDOMNode *aStartNode, { if (!aStartNode || !aEndNode || !aNewParentNode) { return NS_ERROR_NULL_POINTER; } if (gNoisy) { printf("--- start nsTextEditor::MoveContiguousContentIntoNewParent ---\n"); } - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) {DebugDumpContent(); } // DEBUG nsresult result = NS_OK; nsCOMPtrstartNode, endNode; @@ -5301,7 +5310,7 @@ nsHTMLEditor::MoveContiguousContentIntoNewParent(nsIDOMNode *aStartNode, { result = nsEditor::SplitNode(aStartNode, aStartOffset, getter_AddRefs(newLeftNode)); if (gNoisy) { printf("split aStartNode, newLeftNode = %p\n", newLeftNode.get()); } - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) {DebugDumpContent(); } // DEBUG } else { if (gNoisy) { printf("did not split aStartNode\n"); } @@ -5324,7 +5333,7 @@ nsHTMLEditor::MoveContiguousContentIntoNewParent(nsIDOMNode *aStartNode, { result = nsEditor::SplitNode(aEndNode, aEndOffset, getter_AddRefs(newRightNode)); if (gNoisy) { printf("split aEndNode, newRightNode = %p\n", newRightNode.get()); } - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) {DebugDumpContent(); } // DEBUG } else { newRightNode = do_QueryInterface(aEndNode); @@ -5353,8 +5362,8 @@ nsHTMLEditor::MoveContiguousContentIntoNewParent(nsIDOMNode *aStartNode, { // insert aNewParentNode into aGrandParentNode result = nsEditor::InsertNode(aNewParentNode, aGrandParentNode, offsetInParent); - if (gNoisy) printf("just after InsertNode 1\n"); - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) printf("just after InsertNode 1\n"); + if (gNoisy) {DebugDumpContent(); } // DEBUG if (NS_SUCCEEDED(result)) { // move the right half of the start node into the new parent node nsCOMPtrintermediateNode; @@ -5362,14 +5371,14 @@ nsHTMLEditor::MoveContiguousContentIntoNewParent(nsIDOMNode *aStartNode, if (NS_SUCCEEDED(result)) { result = nsEditor::DeleteNode(startNode); - if (gNoisy) printf("just after DeleteNode 1\n"); - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) printf("just after DeleteNode 1\n"); + if (gNoisy) {DebugDumpContent(); } // DEBUG if (NS_SUCCEEDED(result)) { PRInt32 childIndex=0; result = nsEditor::InsertNode(startNode, aNewParentNode, childIndex); - if (gNoisy) printf("just after InsertNode 2\n"); - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) printf("just after InsertNode 2\n"); + if (gNoisy) {DebugDumpContent(); } // DEBUG childIndex++; if (NS_SUCCEEDED(result)) { // move all the intermediate nodes into the new parent node @@ -5384,13 +5393,13 @@ nsHTMLEditor::MoveContiguousContentIntoNewParent(nsIDOMNode *aStartNode, // get the next sibling before moving the current child!!! intermediateNode->GetNextSibling(getter_AddRefs(nextSibling)); result = nsEditor::DeleteNode(intermediateNode); - if (gNoisy) printf("just after DeleteNode 3\n"); - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) printf("just after DeleteNode 3\n"); + if (gNoisy) {DebugDumpContent(); } // DEBUG if (NS_SUCCEEDED(result)) - { + { result = nsEditor::InsertNode(intermediateNode, aNewParentNode, childIndex); - if (gNoisy) printf("just after InsertNode 4\n"); - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) printf("just after InsertNode 4\n"); + if (gNoisy) {DebugDumpContent(); } // DEBUG childIndex++; } intermediateNode = do_QueryInterface(nextSibling); @@ -5398,20 +5407,20 @@ nsHTMLEditor::MoveContiguousContentIntoNewParent(nsIDOMNode *aStartNode, if (NS_SUCCEEDED(result)) { // move the left half of the end node into the new parent node result = nsEditor::DeleteNode(newRightNode); - if (gNoisy) printf("just after DeleteNode 5\n"); - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) printf("just after DeleteNode 5\n"); + if (gNoisy) {DebugDumpContent(); } // DEBUG if (NS_SUCCEEDED(result)) { result = nsEditor::InsertNode(newRightNode, aNewParentNode, childIndex); - if (gNoisy) printf("just after InsertNode 5\n"); - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) printf("just after InsertNode 5\n"); + if (gNoisy) {DebugDumpContent(); } // DEBUG // now set the selection if (NS_SUCCEEDED(result)) { nsCOMPtrselection; result = GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(result)) return result; - if (!selection) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!selection) return NS_ERROR_NULL_POINTER; selection->Collapse(startNode, startOffset); selection->Extend(newRightNode, endOffset); } @@ -5484,8 +5493,8 @@ nsHTMLEditor::SetTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRange, nsCOMPtriter; 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; // find our starting point PRBool startIsText = IsTextNode(aStartNode); @@ -5587,8 +5596,8 @@ nsHTMLEditor::SetTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRange, // create a style node for the text in the start parent nsCOMPtrstartNode = do_QueryInterface(startContent); result = startNode->GetParentNode(getter_AddRefs(parent)); - if (NS_FAILED(result)) return result; - if (!parent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!parent) return NS_ERROR_NULL_POINTER; nsCOMPtrnodeAsChar; nodeAsChar = do_QueryInterface(startNode); @@ -5596,18 +5605,18 @@ nsHTMLEditor::SetTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRange, { nodeAsChar->GetLength(&count); if (gNoisy) { printf("processing start node %p.\n", nodeAsChar.get()); } - if (aStartOffset!=(PRInt32)count) - { - result = SetTextPropertiesForNode(startNode, parent, aStartOffset, count, aPropName, aAttribute, aValue); - startOffset = 0; - } + if (aStartOffset!=(PRInt32)count) + { + result = SetTextPropertiesForNode(startNode, parent, aStartOffset, count, aPropName, aAttribute, aValue); + startOffset = 0; + } } else { nsCOMPtrgrandParent; result = parent->GetParentNode(getter_AddRefs(grandParent)); - if (NS_FAILED(result)) return result; - if (!grandParent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!grandParent) return NS_ERROR_NULL_POINTER; if (gNoisy) { printf("processing start node %p.\n", parent.get()); } result = SetTextPropertiesForNode(parent, grandParent, aStartOffset, aStartOffset+1, aPropName, aAttribute, aValue); startNode = do_QueryInterface(parent); @@ -5628,14 +5637,14 @@ nsHTMLEditor::SetTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRange, { nodeAsChar->GetLength(&count); if (gNoisy) { printf("processing end node %p.\n", nodeAsChar.get()); } - if (0!=aEndOffset) - { - result = SetTextPropertiesForNode(endNode, parent, 0, aEndOffset, aPropName, aAttribute, aValue); - // SetTextPropertiesForNode kindly computed the proper selection focus node and offset for us, - // remember them here - selection->GetFocusOffset(&endOffset); - selection->GetFocusNode(getter_AddRefs(endNode)); - } + if (0!=aEndOffset) + { + result = SetTextPropertiesForNode(endNode, parent, 0, aEndOffset, aPropName, aAttribute, aValue); + // SetTextPropertiesForNode kindly computed the proper selection focus node and offset for us, + // remember them here + selection->GetFocusOffset(&endOffset); + selection->GetFocusNode(getter_AddRefs(endNode)); + } } else { @@ -5643,8 +5652,8 @@ nsHTMLEditor::SetTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRange, if (0==aEndOffset) { return NS_ERROR_NOT_IMPLEMENTED; } nsCOMPtrgrandParent; result = parent->GetParentNode(getter_AddRefs(grandParent)); - if (NS_FAILED(result)) return result; - if (!grandParent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!grandParent) return NS_ERROR_NULL_POINTER; if (gNoisy) { printf("processing end node %p.\n", parent.get()); } result = SetTextPropertiesForNode(parent, grandParent, aEndOffset-1, aEndOffset, aPropName, aAttribute, aValue); endNode = do_QueryInterface(parent); @@ -5889,7 +5898,7 @@ nsHTMLEditor::RemoveTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode, nsIAtom *aPropName, const nsString *aAttribute) { - NS_ASSERTION(0, "obsolete"); + NS_ASSERTION(0, "obsolete"); return NS_ERROR_NOT_IMPLEMENTED; } @@ -5974,8 +5983,8 @@ nsHTMLEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStar if (nodeAsChar) { result = endNode->GetParentNode(getter_AddRefs(parent)); - if (NS_FAILED(result)) return result; - if (!parent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!parent) return NS_ERROR_NULL_POINTER; nodeAsChar->GetLength(&count); if (aEndOffset!=0) { // only do this if at least one child is selected @@ -5997,7 +6006,7 @@ nsHTMLEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStar { skippedEndNode = PR_TRUE; if (gNoisy) { printf("skipping end node because aEndOffset==0\n"); } - } + } } else { @@ -6048,8 +6057,8 @@ nsHTMLEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStar nsCOMPtriter; 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; nsCOMPtrstartContent; startContent = do_QueryInterface(startNode); @@ -6140,8 +6149,8 @@ nsHTMLEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStar } nsCOMPtrselection; result = GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(result)) return result; - if (!selection) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!selection) return NS_ERROR_NULL_POINTER; // set the sel. start point. if we skipped the start node, just use it if (PR_TRUE==skippedStartNode) @@ -6152,7 +6161,7 @@ nsHTMLEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStar // set the sel. end point. if we skipped the end node, just use it if (PR_TRUE==skippedEndNode) endNode = do_QueryInterface(aEndNode); - result = selection->Extend(endNode, rangeEndOffset); + result = selection->Extend(endNode, rangeEndOffset); if (NS_FAILED(result)) return result; if (gNoisy) { printf("RTPFNWDP set selection.\n"); } } @@ -6184,9 +6193,9 @@ nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMSelection *aInSelection) printf("---------- start nsTextEditor::CollapseAdjacentTextNodes ----------\n"); DebugDumpContent(); } - if (!aInSelection) return NS_ERROR_NULL_POINTER; + if (!aInSelection) return NS_ERROR_NULL_POINTER; - nsVoidArray textNodes; // we can't actually do anything during iteration, so store the text nodes in an array + nsVoidArray textNodes; // we can't actually do anything during iteration, so store the text nodes in an array // don't bother ref counting them because we know we can hold them for the // lifetime of this method @@ -6210,7 +6219,7 @@ nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMSelection *aInSelection) anchorText = do_QueryInterface(anchor); if (anchorText) { - textNodes.AppendElement((void*)(anchorText.get())); + textNodes.AppendElement((void*)(anchorText.get())); } aInSelection->GetFocusNode(getter_AddRefs(focus)); focusText = do_QueryInterface(focus); @@ -6245,7 +6254,7 @@ nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMSelection *aInSelection) nsCOMPtr text = do_QueryInterface(content); if (text && anchorText.get() != text.get() && focusText.get() != text.get()) { - textNodes.AppendElement((void*)(text.get())); + textNodes.AppendElement((void*)(text.get())); } iter->Next(); iter->CurrentNode(getter_AddRefs(content)); @@ -6256,18 +6265,18 @@ nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMSelection *aInSelection) // now add the focus to the list, if it's a text node if (focusText) { - textNodes.AppendElement((void*)(focusText.get())); + textNodes.AppendElement((void*)(focusText.get())); } // now that I have a list of text nodes, collapse adjacent text nodes - PRInt32 count = textNodes.Count(); + PRInt32 count = textNodes.Count(); const PRInt32 initialCount = count; - while (1 prevSiblingOfRightTextNode; + // get the prev sibling of the right node, and see if it's leftTextNode + nsCOMPtr prevSiblingOfRightTextNode; result = rightTextNode->GetPreviousSibling(getter_AddRefs(prevSiblingOfRightTextNode)); if (NS_FAILED(result)) return result; if (prevSiblingOfRightTextNode) @@ -6335,7 +6344,7 @@ nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMSelection *aInSelection) // remove the rightmost remaining text node from the array and work our way towards the beginning textNodes.RemoveElementAt(0); // remove the leftmost text node from the list count --; - } + } ResetTextSelectionForRange(parentForSelection, rangeStartOffset, rangeEndOffset, aInSelection); @@ -6345,6 +6354,6 @@ nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMSelection *aInSelection) DebugDumpContent(); } - return result; + return result; } diff --git a/editor/base/nsHTMLEditor.h b/editor/base/nsHTMLEditor.h index c606d3332e3..07f5c1fc00c 100644 --- a/editor/base/nsHTMLEditor.h +++ b/editor/base/nsHTMLEditor.h @@ -243,7 +243,7 @@ protected: // key event helpers NS_IMETHOD TabInTable(PRBool inIsShift, PRBool *outHandled); - NS_IMETHOD InsertBR(); + NS_IMETHOD InsertBR(nsCOMPtr *outBRNode); // Table Editing (implemented in EditTable.cpp) @@ -474,6 +474,9 @@ protected: PRBool mIsComposing; PRInt32 mMaxTextLength; +public: + static nsIAtom *gTypingTxnName; + // friends friend class nsHTMLEditRules; friend class nsTextEditRules; diff --git a/editor/base/nsTextEditRules.cpp b/editor/base/nsTextEditRules.cpp index ab31f53b0cf..eb3cd851935 100644 --- a/editor/base/nsTextEditRules.cpp +++ b/editor/base/nsTextEditRules.cpp @@ -19,8 +19,6 @@ #include "nsTextEditRules.h" #include "nsEditor.h" -#include "PlaceholderTxn.h" -#include "InsertTextTxn.h" #include "nsCOMPtr.h" #include "nsIDOMNode.h" @@ -140,7 +138,6 @@ nsTextEditRules::WillDoAction(nsIDOMSelection *aSelection, case kInsertText: return WillInsertText(aSelection, aCancel, - info->placeTxn, info->inString, info->outString, info->typeInState, @@ -265,7 +262,6 @@ nsTextEditRules::DidInsertBreak(nsIDOMSelection *aSelection, nsresult aResult) nsresult nsTextEditRules::WillInsertText(nsIDOMSelection *aSelection, PRBool *aCancel, - PlaceholderTxn **aTxn, const nsString *aInString, nsString *aOutString, TypeInState aTypeInState, @@ -293,7 +289,7 @@ nsTextEditRules::WillInsertText(nsIDOMSelection *aSelection, // do text insertion PRBool bCancel; - res = DoTextInsertion(aSelection, &bCancel, aTxn, aOutString, aTypeInState); + res = DoTextInsertion(aSelection, &bCancel, aOutString, aTypeInState); return res; } @@ -1059,7 +1055,6 @@ nsTextEditRules::EchoInsertionToPWBuff(nsIDOMSelection *aSelection, nsString *aO nsresult nsTextEditRules::DoTextInsertion(nsIDOMSelection *aSelection, PRBool *aCancel, - PlaceholderTxn **aTxn, const nsString *aInString, TypeInState aTypeInState) { @@ -1070,14 +1065,6 @@ nsTextEditRules::DoTextInsertion(nsIDOMSelection *aSelection, // 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)) diff --git a/editor/base/nsTextEditRules.h b/editor/base/nsTextEditRules.h index 0fa8df0cac9..66f08dfde90 100644 --- a/editor/base/nsTextEditRules.h +++ b/editor/base/nsTextEditRules.h @@ -27,7 +27,6 @@ #include "nsEditRules.h" #include "TypeInState.h" -class PlaceholderTxn; class nsTextEditor; /** Object that encapsulates HTML text-specific editing rules. @@ -86,7 +85,6 @@ protected: // nsTextEditRules implementation methods nsresult WillInsertText(nsIDOMSelection *aSelection, PRBool *aCancel, - PlaceholderTxn **aTxn, const nsString *inString, nsString *outString, TypeInState typeInState, @@ -180,7 +178,6 @@ protected: /** do the actual text insertion */ nsresult DoTextInsertion(nsIDOMSelection *aSelection, PRBool *aCancel, - PlaceholderTxn **aTxn, const nsString *aInString, TypeInState aTypeInState); @@ -199,7 +196,6 @@ class nsTextRulesInfo : public nsRulesInfo nsTextRulesInfo(int aAction) : nsRulesInfo(aAction), - placeTxn(0), inString(0), outString(0), outputFormat(0), @@ -215,7 +211,6 @@ class nsTextRulesInfo : public nsRulesInfo virtual ~nsTextRulesInfo() {}; // kInsertText - PlaceholderTxn **placeTxn; const nsString *inString; nsString *outString; const nsString *outputFormat; diff --git a/editor/libeditor/base/PlaceholderTxn.cpp b/editor/libeditor/base/PlaceholderTxn.cpp index 6201acfcaad..4e8f353b2a4 100644 --- a/editor/libeditor/base/PlaceholderTxn.cpp +++ b/editor/libeditor/base/PlaceholderTxn.cpp @@ -18,6 +18,8 @@ #include "PlaceholderTxn.h" #include "nsVoidArray.h" +#include "nsHTMLEditor.h" +#include "nsIPresShell.h" #if defined(NS_DEBUG) && defined(DEBUG_buster) static PRBool gNoisy = PR_TRUE; @@ -26,10 +28,11 @@ static const PRBool gNoisy = PR_FALSE; #endif -PlaceholderTxn::PlaceholderTxn() - : EditAggregateTxn() +PlaceholderTxn::PlaceholderTxn() : EditAggregateTxn(), + mPresShellWeak(nsnull), + mAbsorb(PR_TRUE), + mForwarding(nsnull) { - mAbsorb=PR_TRUE; SetTransactionDescriptionID( kTransactionID ); /* log description initialized in parent constructor */ } @@ -39,39 +42,153 @@ PlaceholderTxn::~PlaceholderTxn() { } +NS_IMPL_ADDREF_INHERITED(PlaceholderTxn, EditAggregateTxn) +NS_IMPL_RELEASE_INHERITED(PlaceholderTxn, EditAggregateTxn) + +//NS_IMPL_QUERY_INTERFACE_INHERITED(Class, Super, AdditionalInterface) +NS_IMETHODIMP PlaceholderTxn::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (!aInstancePtr) return NS_ERROR_NULL_POINTER; + + if (aIID.Equals(nsIAbsorbingTransaction::GetIID())) { + *aInstancePtr = (nsISupports*)(nsIAbsorbingTransaction*)(this); + NS_ADDREF_THIS(); + return NS_OK; + } + if (aIID.Equals(nsCOMTypeInfo::GetIID())) { + *aInstancePtr = (nsISupports*)(nsISupportsWeakReference*) this; + NS_ADDREF_THIS(); + return NS_OK; + } + return EditAggregateTxn::QueryInterface(aIID, aInstancePtr); +} + +NS_IMETHODIMP PlaceholderTxn::Init(nsWeakPtr aPresShellWeak, nsIAtom *aName, + nsIDOMNode *aStartNode, PRInt32 aStartOffset) +{ + NS_ASSERTION(aPresShellWeak, "bad args"); + if (!aPresShellWeak) return NS_ERROR_NULL_POINTER; + + mPresShellWeak = aPresShellWeak; + mName = aName; + mStartNode = do_QueryInterface(aStartNode); + mStartOffset = aStartOffset; + return NS_OK; +} + NS_IMETHODIMP PlaceholderTxn::Do(void) { if (gNoisy) { printf("PlaceholderTxn Do\n"); } return NS_OK; } +NS_IMETHODIMP PlaceholderTxn::Undo(void) +{ + // using this to debug + return EditAggregateTxn::Undo(); +} + + NS_IMETHODIMP PlaceholderTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransaction) { + if (!aDidMerge || !aTransaction) return NS_ERROR_NULL_POINTER; + // set out param default value - if (nsnull!=aDidMerge) - *aDidMerge=PR_FALSE; - nsresult result = NS_OK; - if ((nsnull!=aDidMerge) && (nsnull!=aTransaction)) + *aDidMerge=PR_FALSE; + + nsresult res = NS_OK; + + if (mForwarding) { - EditTxn *editTxn = (EditTxn*)aTransaction; //XXX: hack, not safe! need nsIEditTransaction! - if (PR_TRUE==mAbsorb) - { // yep, it's one of ours. Assimilate it. - AppendChild(editTxn); - *aDidMerge = PR_TRUE; - if (gNoisy) { printf("Placeholder txn assimilated %p\n", aTransaction); } - } - else - { // let our last child txn make the choice - PRInt32 count = mChildren->Count(); - if (0 plcTxn;// = do_QueryInterface(editTxn); + // cant do_QueryInterface() above due to our broken transaction interfaces. + // instead have to brute it below. ugh. + editTxn->QueryInterface(nsIAbsorbingTransaction::GetIID(), getter_AddRefs(plcTxn)); + if (plcTxn) { - EditTxn *lastTxn = (EditTxn*)(mChildren->ElementAt(count-1)); - if (lastTxn) + nsIAtom *atom; + plcTxn->GetTxnName(&atom); + if (atom && (atom == nsHTMLEditor::gTypingTxnName)) { - lastTxn->Merge(aDidMerge, aTransaction); + nsCOMPtr otherTxnStartNode; + PRInt32 otherTxnStartOffset; + res = plcTxn->GetStartNodeAndOffset(&otherTxnStartNode, &otherTxnStartOffset); + if (NS_FAILED(res)) return res; + + if ((otherTxnStartNode == mEndNode) && (otherTxnStartOffset == mEndOffset)) + { + mAbsorb = PR_TRUE; // we need to start absorbing again + plcTxn->ForwardEndBatchTo(this); + AppendChild(editTxn); + *aDidMerge = PR_TRUE; + } } } } } - return result; + return res; } + +NS_IMETHODIMP PlaceholderTxn::GetTxnName(nsIAtom **aName) +{ + return GetName(aName); +} + +NS_IMETHODIMP PlaceholderTxn::GetStartNodeAndOffset(nsCOMPtr *aTxnStartNode, PRInt32 *aTxnStartOffset) +{ + if (!aTxnStartNode || !aTxnStartOffset) return NS_ERROR_NULL_POINTER; + *aTxnStartNode = mStartNode; + *aTxnStartOffset = mStartOffset; + return NS_OK; +} + +NS_IMETHODIMP PlaceholderTxn::EndPlaceHolderBatch() +{ + mAbsorb = PR_FALSE; + + if (mForwarding) + { + nsCOMPtr plcTxn = do_QueryReferent(mForwarding); + if (plcTxn) plcTxn->EndPlaceHolderBatch(); + } + + // if we are a typing transaction, remember our selection state + if (mName.get() == nsHTMLEditor::gTypingTxnName) + { + nsCOMPtr ps = do_QueryReferent(mPresShellWeak); + if (!ps) return NS_ERROR_NOT_INITIALIZED; + nsCOMPtr selection; + nsresult res = ps->GetSelection(SELECTION_NORMAL, getter_AddRefs(selection)); + if (NS_FAILED(res)) return res; + if (!selection) return NS_ERROR_NULL_POINTER; + res = nsEditor::GetStartNodeAndOffset(selection, &mEndNode, &mEndOffset); + if (NS_FAILED(res)) return res; + } + return NS_OK; +}; + +NS_IMETHODIMP PlaceholderTxn::ForwardEndBatchTo(nsIAbsorbingTransaction *aForwardingAddress) +{ + mForwarding = getter_AddRefs( NS_GetWeakReference(aForwardingAddress) ); + return NS_OK; +} + + + + + diff --git a/editor/libeditor/base/PlaceholderTxn.h b/editor/libeditor/base/PlaceholderTxn.h index 3d214e34d30..5ad13ec7d02 100644 --- a/editor/libeditor/base/PlaceholderTxn.h +++ b/editor/libeditor/base/PlaceholderTxn.h @@ -20,24 +20,36 @@ #define AggregatePlaceholderTxn_h__ #include "EditAggregateTxn.h" +#include "nsIAbsorbingTransaction.h" +#include "nsIDOMNode.h" +#include "nsCOMPtr.h" +#include "nsWeakPtr.h" +#include "nsWeakReference.h" #define PLACEHOLDER_TXN_CID \ {/* {0CE9FB00-D9D1-11d2-86DE-000064657374} */ \ 0x0CE9FB00, 0xD9D1, 0x11d2, \ {0x86, 0xde, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} } +class nsHTMLEditor; + /** * An aggregate transaction that knows how to absorb all subsequent * transactions with the same name. This transaction does not "Do" anything. * But it absorbs other transactions via merge, and can undo/redo the * transactions it has absorbed. */ -class PlaceholderTxn : public EditAggregateTxn + +class PlaceholderTxn : public EditAggregateTxn, + public nsIAbsorbingTransaction, + public nsSupportsWeakReference { public: static const nsIID& GetCID() { static nsIID iid = PLACEHOLDER_TXN_CID; return iid; } + NS_DECL_ISUPPORTS_INHERITED + private: PlaceholderTxn(); @@ -45,11 +57,25 @@ public: virtual ~PlaceholderTxn(); +// ------------ EditAggregateTxn ----------------------- + NS_IMETHOD Do(void); + NS_IMETHOD Undo(void); + NS_IMETHOD Merge(PRBool *aDidMerge, nsITransaction *aTransaction); - NS_IMETHOD SetAbsorb(PRBool aAbsorb); +// ------------ nsIAbsorbingTransaction ----------------------- + + NS_IMETHOD Init(nsWeakPtr aPresShellWeak, nsIAtom *aName, nsIDOMNode *aStartNode, PRInt32 aStartOffset); + + NS_IMETHOD GetTxnName(nsIAtom **aName); + + NS_IMETHOD GetStartNodeAndOffset(nsCOMPtr *aTxnStartNode, PRInt32 *aTxnStartOffset); + + NS_IMETHOD EndPlaceHolderBatch(); + + NS_IMETHOD ForwardEndBatchTo(nsIAbsorbingTransaction *aForwardingAddress); friend class TransactionFactory; @@ -57,14 +83,12 @@ public: protected: - PRBool mAbsorb; - -}; - -inline NS_IMETHODIMP PlaceholderTxn::SetAbsorb(PRBool aAbsorb) -{ - mAbsorb = aAbsorb; - return NS_OK; + /** the presentation shell, which we'll need to get the selection */ + nsWeakPtr mPresShellWeak; // weak reference to the nsIPresShell + PRBool mAbsorb; + nsCOMPtr mStartNode, mEndNode; // selection nodes at beginning and end of operation + PRInt32 mStartOffset, mEndOffset; // selection offsets at beginning and end of operation + nsWeakPtr mForwarding; }; diff --git a/editor/libeditor/base/nsEditor.cpp b/editor/libeditor/base/nsEditor.cpp index 828fbef5b3c..d85b6a60706 100644 --- a/editor/libeditor/base/nsEditor.cpp +++ b/editor/libeditor/base/nsEditor.cpp @@ -36,6 +36,7 @@ #include "nsIServiceManager.h" #include "nsTransactionManagerCID.h" #include "nsITransactionManager.h" +#include "nsIAbsorbingTransaction.h" #include "nsIPresShell.h" #include "nsIPresContext.h" #include "nsIViewManager.h" @@ -54,6 +55,7 @@ #include "nsIDocumentObserver.h" #include "nsIDocumentStateListener.h" #include "nsIStringStream.h" +#include "nsITextContent.h" #ifdef NECKO #include "nsNeckoUtil.h" @@ -68,6 +70,7 @@ // transactions the editor knows how to build #include "TransactionFactory.h" #include "EditAggregateTxn.h" +#include "PlaceholderTxn.h" #include "ChangeAttributeTxn.h" #include "CreateElementTxn.h" #include "InsertElementTxn.h" @@ -85,6 +88,7 @@ #include "nsEditorCID.h" #include "nsEditor.h" +#include "nsEditorUtils.h" #ifdef HACK_FORCE_REDRAW @@ -143,6 +147,12 @@ nsEditor::nsEditor() , mActionListeners(nsnull) , mDocDirtyState(-1) , mDocWeak(nsnull) +, mPlaceHolderTxn(nsnull) +, mPlaceHolderName(nsnull) +, mPlaceHolderBatch(0) +, mTxnStartNode(nsnull) +, mTxnStartOffset(0) + { //initialize member variables here NS_INIT_REFCNT(); @@ -332,6 +342,31 @@ nsEditor::Do(nsITransaction *aTxn) { if (gNoisy) { printf("Editor::Do ----------\n"); } nsresult result = NS_OK; + + if (mPlaceHolderBatch && !mPlaceHolderTxn) + { + // it's pretty darn amazing how many different types of pointers + // this transcation goes through here. I bet this is a record. + EditTxn *editTxn; + nsCOMPtr plcTxn; + result = TransactionFactory::GetNewTransaction(PlaceholderTxn::GetCID(), &editTxn); + if (NS_FAILED(result)) { return result; } + if (!editTxn) { return NS_ERROR_NULL_POINTER; } + editTxn->QueryInterface(nsIAbsorbingTransaction::GetIID(), getter_AddRefs(plcTxn)); + // have to use line above instead of line below due to our broken + // interface model for transactions. +// plcTxn = do_QueryInterface(editTxn); + // save off weak reference to placeholder txn + mPlaceHolderTxn = getter_AddRefs( NS_GetWeakReference(plcTxn) ); + plcTxn->Init(mPresShellWeak, mPlaceHolderName, mTxnStartNode, mTxnStartOffset); + // we will recurse, but will not hit this case in the nested call + nsCOMPtr theTxn = do_QueryInterface(plcTxn); + nsITransaction* txn = theTxn; + // we want to escape from this routine with a positive refcount + txn->AddRef(); + Do(txn); + } + nsCOMPtrselection; nsresult selectionResult = GetSelection(getter_AddRefs(selection)); if (NS_SUCCEEDED(selectionResult) && selection) { @@ -504,6 +539,72 @@ nsEditor::EndTransaction() return NS_OK; } + +// These two routines are similar to the above, but do not use +// the transaction managers batching feature. Instead we use +// a placeholder transaction to wrap up any further transaction +// while the batch is open. The advantage of this is that +// placeholder transactions can later merge, if needed. Merging +// is unavailable between transaction manager batches. + +NS_IMETHODIMP +nsEditor::BeginPlaceHolderTransaction(nsIAtom *aName) +{ + NS_PRECONDITION(mPlaceHolderBatch >= 0, "negative placeholder batch count!"); + if (!mPlaceHolderBatch) + { + // time to turn on the batch + BeginUpdateViewBatch(); + mPlaceHolderTxn = nsnull; + mPlaceHolderName = aName; + nsCOMPtr selection; + nsresult res = GetSelection(getter_AddRefs(selection)); + if (NS_FAILED(res)) return res; + PRBool collapsed; + res = selection->GetIsCollapsed(&collapsed); + if (NS_FAILED(res)) return res; + if (collapsed) // we cant merge with previous typing if selection not collapsed + { + // need to remember colapsed selection point to Init the placeholder with later. + // this is because we dont actually make the placeholder until we need it, and we + // might have moved the selection as part of the typing processing by then. + res = GetStartNodeAndOffset(selection, &mTxnStartNode, &mTxnStartOffset); + if (NS_FAILED(res)) return res; + } + } + mPlaceHolderBatch++; + + return NS_OK; +} + +NS_IMETHODIMP +nsEditor::EndPlaceHolderTransaction() +{ + NS_PRECONDITION(mPlaceHolderBatch > 0, "zero or negative placeholder batch count when ending batch!"); + if (mPlaceHolderBatch == 1) + { + // time to turn off the batch + EndUpdateViewBatch(); + mTxnStartNode = nsnull; + mTxnStartOffset = 0; + if (mPlaceHolderTxn) // we might have never made a placeholder if no action took place + { + nsCOMPtr plcTxn = do_QueryReferent(mPlaceHolderTxn); + if (plcTxn) + { + plcTxn->EndPlaceHolderBatch(); + } + else // but if we did make one it should be around + { + NS_NOTREACHED("should this ever happen?"); + } + } + } + mPlaceHolderBatch--; + + return NS_OK; +} + // XXX: the rule system should tell us which node to select all on (ie, the root, or the body) NS_IMETHODIMP nsEditor::SelectAll() { @@ -1489,8 +1590,9 @@ NS_IMETHODIMP nsEditor::InsertTextImpl(const nsString& aStringToInsert) result = CreateTxnForInsertText(aStringToInsert, nsnull, &txn); // insert at the current selection if ((NS_SUCCEEDED(result)) && txn) { BeginUpdateViewBatch(); - aggTxn->AppendChild(txn); +// aggTxn->AppendChild(txn); result = Do(aggTxn); + result = Do(txn); EndUpdateViewBatch(); } else if (NS_ERROR_EDITOR_NO_SELECTION==result) { @@ -1769,7 +1871,7 @@ NS_IMETHODIMP nsEditor::CreateTxnForInsertText(const nsString & aStringToInsert, // This may be OK, now that I fixed InsertText so it inserts // at the offset of the selection anchor (i.e., the caret offset) // instead of at offset+1 - PRBool collapsed + PRBool collapsed; result = selection->GetIsCollapsed(&collapsed); if (NS_SUCCEEDED(result) && collapsed) { @@ -2559,8 +2661,8 @@ nsEditor::GetPriorNode(nsIDOMNode *aParentNode, nsresult result = NS_OK; if (!aParentNode || !aResultNode) { return NS_ERROR_NULL_POINTER; } - // if we are at beginning of node than just look before it - if (!aOffset) + // if we are at beginning of node, or it is a textnode, then just look before it + if (!aOffset || IsTextNode(aParentNode)) { return GetPriorNode(aParentNode, aEditableNode, aResultNode); } @@ -2601,6 +2703,14 @@ nsEditor::GetNextNode(nsIDOMNode *aParentNode, nsresult result = NS_OK; if (!aParentNode || !aResultNode) { return NS_ERROR_NULL_POINTER; } + // if aParentNode is a text node, use it's location instead + if (IsTextNode(aParentNode)) + { + nsCOMPtr parent; + nsEditor::GetNodeLocation(aParentNode, &parent, &aOffset); + aParentNode = parent; + aOffset++; // _after_ the text node + } // look at the child at 'aOffset' nsCOMPtr child = GetChildAt(aParentNode, aOffset); if (child) @@ -2828,6 +2938,18 @@ nsEditor::CanContainTag(nsIDOMNode* aParent, const nsString &aTag) return mDTD->CanContain(parentTagEnum, childTagEnum); } +PRBool +nsEditor::IsContainer(nsIDOMNode *aNode) +{ + if (!aNode) return PR_FALSE; + nsAutoString stringTag; + PRInt32 tagEnum; + nsresult res = aNode->GetNodeName(stringTag); + if (NS_FAILED(res)) return PR_FALSE; + res = mDTD->StringTagToIntTag(stringTag,&tagEnum); + if (NS_FAILED(res)) return PR_FALSE; + return mDTD->IsContainer(tagEnum); +} PRBool nsEditor::IsEditable(nsIDOMNode *aNode) @@ -2885,13 +3007,27 @@ nsEditor::IsEditable(nsIDOMNode *aNode) if (NS_FAILED(result) || !resultFrame) { // if it has no frame, it is not editable return PR_FALSE; } - else { // it has a frame, so it is editable + else { + // it has a frame, so it might editable + // but not if it's a formatting whitespace node + if (IsEmptyTextContent(content)) return PR_FALSE; return PR_TRUE; } } return PR_FALSE; // it's not a content object (???) so it's not editable } +PRBool +nsEditor::IsEmptyTextContent(nsIContent* aContent) +{ + PRBool result = PR_FALSE; + nsCOMPtr tc(do_QueryInterface(aContent)); + if (tc) { + tc->IsOnlyWhitespace(&result); + } + return result; +} + nsresult nsEditor::CountEditableChildren(nsIDOMNode *aNode, PRUint32 &outCount) { @@ -3108,7 +3244,7 @@ nsEditor::SetInputMethodText(const nsString& aStringToInsert, nsIPrivateTextRang } else if (NS_ERROR_EDITOR_NO_TEXTNODE==result) { - BeginTransaction(); + nsAutoEditBatch batchIt (this); nsCOMPtr selection; result = GetSelection(getter_AddRefs(selection)); if ((NS_SUCCEEDED(result)) && selection) @@ -3138,8 +3274,6 @@ nsEditor::SetInputMethodText(const nsString& aStringToInsert, nsIPrivateTextRang } } } - - EndTransaction(); } return result; diff --git a/editor/libeditor/base/nsEditor.h b/editor/libeditor/base/nsEditor.h index 219c9a1f31a..fdc234c9a3a 100644 --- a/editor/libeditor/base/nsEditor.h +++ b/editor/libeditor/base/nsEditor.h @@ -121,6 +121,9 @@ public: NS_IMETHOD BeginTransaction(); NS_IMETHOD EndTransaction(); + NS_IMETHOD BeginPlaceHolderTransaction(nsIAtom *aName); + NS_IMETHOD EndPlaceHolderTransaction(); + // pure virtual, because the definition of 'empty' depends on the doc type NS_IMETHOD GetDocumentIsEmpty(PRBool *aDocumentIsEmpty)=0; @@ -553,11 +556,17 @@ public: static PRBool NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag); /** returns PR_TRUE if aParent can contain a child of type aTag */ - PRBool CanContainTag(nsIDOMNode* aParent, const nsString &aTag); + PRBool CanContainTag(nsIDOMNode* aParent, const nsString &aTag); + /** returns PR_TRUE if aNode is a container */ + PRBool IsContainer(nsIDOMNode *aNode); + /** returns PR_TRUE if aNode is an editable node */ PRBool IsEditable(nsIDOMNode *aNode); + /** returns PR_TRUE if content is an merely formatting whitespacce */ + PRBool IsEmptyTextContent(nsIContent* aContent); + /** counts number of editable child nodes */ nsresult CountEditableChildren(nsIDOMNode *aNode, PRUint32 &outCount); @@ -608,6 +617,11 @@ protected: nsCOMPtr mTxnMgr; nsCOMPtr mEditProperty; nsCOMPtr mLastStyleSheet; // is owning this dangerous? + nsWeakPtr mPlaceHolderTxn; + nsIAtom *mPlaceHolderName; + PRInt32 mPlaceHolderBatch; + nsCOMPtr mTxnStartNode; + PRInt32 mTxnStartOffset; // // data necessary to build IME transactions diff --git a/editor/libeditor/base/nsEditorUtils.h b/editor/libeditor/base/nsEditorUtils.h index 5c7c07844b6..5d2c64e4f5b 100644 --- a/editor/libeditor/base/nsEditorUtils.h +++ b/editor/libeditor/base/nsEditorUtils.h @@ -25,6 +25,7 @@ #include "nsIDOMNode.h" #include "nsIDOMSelection.h" #include "nsIEditor.h" +#include "nsIAtom.h" class nsAutoEditBatch { @@ -43,11 +44,21 @@ class nsAutoEditMayBatch PRBool mDidBatch; public: nsAutoEditMayBatch( nsIEditor *aEd) : mEd(do_QueryInterface(aEd)), mDidBatch(PR_FALSE) {} - nsAutoEditMayBatch() { if (mEd && mDidBatch) mEd->EndTransaction(); } + ~nsAutoEditMayBatch() { if (mEd && mDidBatch) mEd->EndTransaction(); } void batch() { if (mEd && !mDidBatch) {mEd->BeginTransaction(); mDidBatch=PR_TRUE;} } }; +class nsAutoPlaceHolderBatch +{ + private: + nsCOMPtr mEd; + public: + nsAutoPlaceHolderBatch( nsIEditor *aEd, nsIAtom *atom) : mEd(do_QueryInterface(aEd)) + { if (mEd) mEd->BeginPlaceHolderTransaction(atom); } + ~nsAutoPlaceHolderBatch() { if (mEd) mEd->EndPlaceHolderTransaction(); } +}; + class nsAutoSelectionReset { diff --git a/editor/libeditor/html/nsHTMLEditRules.cpp b/editor/libeditor/html/nsHTMLEditRules.cpp index 0211e3c89c4..639d3c465d1 100644 --- a/editor/libeditor/html/nsHTMLEditRules.cpp +++ b/editor/libeditor/html/nsHTMLEditRules.cpp @@ -21,9 +21,6 @@ #include "nsEditor.h" #include "nsHTMLEditor.h" -#include "PlaceholderTxn.h" -#include "InsertTextTxn.h" - #include "nsIContent.h" #include "nsIContentIterator.h" #include "nsIDOMNode.h" @@ -90,7 +87,6 @@ nsHTMLEditRules::WillDoAction(nsIDOMSelection *aSelection, case kInsertText: return WillInsertText(aSelection, aCancel, - info->placeTxn, info->inString, info->outString, info->typeInState, @@ -127,11 +123,13 @@ nsHTMLEditRules::DidDoAction(nsIDOMSelection *aSelection, switch (info->action) { - case kInsertBreak: - return NS_OK; + case kUndo: + return nsTextEditRules::DidDoAction(aSelection, aInfo, aResult); + case kRedo: + return nsTextEditRules::DidDoAction(aSelection, aInfo, aResult); } - // clean up any empty nodes in the selection + // other than undo and redo, clean up any empty nodes in the selection CleanUpSelection(aSelection); return nsTextEditRules::DidDoAction(aSelection, aInfo, aResult); @@ -145,7 +143,6 @@ nsHTMLEditRules::DidDoAction(nsIDOMSelection *aSelection, nsresult nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection, PRBool *aCancel, - PlaceholderTxn **aTxn, const nsString *inString, nsString *outString, TypeInState typeInState, @@ -155,7 +152,8 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection, // initialize out param *aCancel = PR_TRUE; nsresult res; - nsAutoEditMayBatch optionalBatch; + nsCOMPtr selNode; + PRInt32 selOffset; char specialChars[] = {'\t',' ',nbsp,'\n',0}; @@ -169,20 +167,27 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection, if (NS_FAILED(res)) return res; } + // get the (collapsed) selection location + res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset); + if (NS_FAILED(res)) return res; + + res = WillInsert(aSelection, aCancel); + if (NS_FAILED(res)) return res; + + // initialize out param + // we want to ignore result of WillInsert() + *aCancel = PR_TRUE; + // split any mailcites in the way - if (1 || mFlags & nsIHTMLEditor::eEditorMailMask) + if (mFlags & nsIHTMLEditor::eEditorMailMask) { - nsCOMPtr citeNode, selNode; - PRInt32 selOffset, newOffset; - res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset); - if (NS_FAILED(res)) return res; + nsCOMPtr citeNode; + PRInt32 newOffset; res = GetTopEnclosingMailCite(selNode, &citeNode); if (NS_FAILED(res)) return res; if (citeNode) { - // turn batching on - optionalBatch.batch(); res = mEditor->SplitNodeDeep(citeNode, selNode, selOffset, &newOffset); if (NS_FAILED(res)) return res; res = citeNode->GetParentNode(getter_AddRefs(selNode)); @@ -192,9 +197,73 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection, } } + // identify the block + nsCOMPtr blockParent; + + if (nsEditor::IsBlockNode(selNode)) + blockParent = selNode; + else + blockParent = mEditor->GetBlockNodeParent(selNode); + if (!blockParent) return NS_ERROR_FAILURE; + + // are we not in a textnode? + if (!mEditor->IsTextNode(selNode)) + { + // find a nearby text node if possible + nsCOMPtr priorNode, nextNode; + res = GetPriorHTMLNode(selNode, selOffset, &priorNode); + if (NS_SUCCEEDED(res) && priorNode && mEditor->IsTextNode(priorNode) + && (blockParent == mEditor->GetBlockNodeParent(priorNode))) + { + // put selection at end of prior node + PRUint32 strLength; + nsCOMPtr textNode = do_QueryInterface(priorNode); + res = textNode->GetLength(&strLength); + if (NS_FAILED(res)) return res; + res = aSelection->Collapse(priorNode, strLength); + if (NS_FAILED(res)) return res; + } + else + { + res = GetNextHTMLNode(selNode, selOffset, &nextNode); + if (NS_SUCCEEDED(res) && nextNode && mEditor->IsTextNode(nextNode) + && (blockParent == mEditor->GetBlockNodeParent(nextNode))) + { + // put selection at begining of next node + res = aSelection->Collapse(nextNode, 0); + if (NS_FAILED(res)) return res; + } + } + + // if we are right after a moz br, delete it and make a new moz div + PRBool needMozDiv = PR_FALSE; + if (priorNode && IsBreak(priorNode) && HasMozAttr(priorNode) + && (blockParent == mEditor->GetBlockNodeParent(priorNode))) + { + needMozDiv = PR_TRUE; + res = mEditor->DeleteNode(priorNode); + if (NS_FAILED(res)) return res; + } + + // if we are directly in a body or (non-moz) div, create a moz-div. + // Also creat one if we detected a prior moz br (see above). + res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset); + if (NS_FAILED(res)) return res; + if (needMozDiv || IsBody(selNode) || IsNormalDiv(selNode)) + { + // wrap things up in a moz-div + nsCOMPtr mozDiv; + res = CreateMozDiv(selNode, selOffset, &mozDiv); + if (NS_FAILED(res)) return res; + // put selection in it + res = aSelection->Collapse(mozDiv, 0); + if (NS_FAILED(res)) return res; + } + } + char nbspStr[2] = {nbsp, 0}; - nsString theString(*inString); // copy instr for now + nsString theString(*inString); // copy instring for now PRInt32 pos = theString.FindCharInSet(specialChars); while (theString.Length()) { @@ -208,23 +277,23 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection, // is it a solo tab? if (partialString == "\t" ) { - res = InsertTab(aSelection,&bCancel,aTxn,outString); + res = InsertTab(aSelection,&bCancel,outString); if (NS_FAILED(res)) return res; - res = DoTextInsertion(aSelection, aCancel, aTxn, outString, typeInState); + res = DoTextInsertion(aSelection, aCancel, outString, typeInState); } // is it a solo space? else if (partialString == " ") { - res = InsertSpace(aSelection,&bCancel,aTxn,outString); + res = InsertSpace(aSelection,&bCancel,outString); if (NS_FAILED(res)) return res; - res = DoTextInsertion(aSelection, aCancel, aTxn, outString, typeInState); + res = DoTextInsertion(aSelection, aCancel, outString, typeInState); } // is it a solo nbsp? else if (partialString == nbspStr) { - res = InsertSpace(aSelection,&bCancel,aTxn,outString); + res = InsertSpace(aSelection,&bCancel,outString); if (NS_FAILED(res)) return res; - res = DoTextInsertion(aSelection, aCancel, aTxn, outString, typeInState); + res = DoTextInsertion(aSelection, aCancel, outString, typeInState); } // is it a solo return? else if (partialString == "\n") @@ -233,7 +302,7 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection, } else { - res = DoTextInsertion(aSelection, aCancel, aTxn, &partialString, typeInState); + res = DoTextInsertion(aSelection, aCancel, &partialString, typeInState); } if (NS_FAILED(res)) return res; pos = theString.FindCharInSet(specialChars); @@ -250,7 +319,6 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel) *aCancel = PR_FALSE; nsresult res; - nsAutoEditMayBatch optionalBatch; res = WillInsert(aSelection, aCancel); if (NS_FAILED(res)) return res; @@ -269,7 +337,7 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel) } // split any mailcites in the way - if (1 || mFlags & nsIHTMLEditor::eEditorMailMask) + if (mFlags & nsIHTMLEditor::eEditorMailMask) { nsCOMPtr citeNode, selNode; PRInt32 selOffset, newOffset; @@ -280,8 +348,6 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel) if (citeNode) { - // turn batching on - optionalBatch.batch(); res = mEditor->SplitNodeDeep(citeNode, selNode, selOffset, &newOffset); if (NS_FAILED(res)) return res; res = citeNode->GetParentNode(getter_AddRefs(selNode)); @@ -310,6 +376,7 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel) return mEditor->InsertTextImpl(theString); } + // identify the block nsCOMPtr blockParent; if (nsEditor::IsBlockNode(node)) @@ -319,8 +386,67 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel) if (!blockParent) return NS_ERROR_FAILURE; + // break action depends on type of block + PRBool bIsMozDiv = IsMozDiv(blockParent); + PRBool bIsNormalDiv = IsNormalDiv(blockParent); + + // body, div, or mozdiv: insert a moz br + if (IsBody(blockParent) || bIsNormalDiv || + (bIsMozDiv && AtEndOfBlock(node, offset, blockParent))) + { + if (bIsMozDiv) + { + // put selection beyond the mozdiv first + nsCOMPtr parent; + PRInt32 pOffset; + res = nsEditor::GetNodeLocation(blockParent, &parent, &pOffset); + if (NS_FAILED(res)) return res; + if (!parent) return NS_ERROR_FAILURE; + res = aSelection->Collapse(parent, pOffset+1); + if (NS_FAILED(res)) return res; + } + nsCOMPtr brNode; + res = mEditor->InsertBR(&brNode); // only inserts a br node + if (NS_FAILED(res)) return res; + // give it special moz attr + nsCOMPtr brElem = do_QueryInterface(brNode); + if (brElem) + { + res = mEditor->SetAttribute(brElem, "type", "_moz"); + if (NS_FAILED(res)) return res; + } + *aCancel = PR_TRUE; + } + else if (bIsMozDiv && AtStartOfBlock(node, offset, blockParent)) + { + // position selection in front of mozdiv, and let default code + // make a normal br + nsCOMPtr parent; + PRInt32 pOffset; + res = nsEditor::GetNodeLocation(blockParent, &parent, &pOffset); + if (NS_FAILED(res)) return res; + if (!parent) return NS_ERROR_FAILURE; + res = aSelection->Collapse(parent, pOffset); + if (NS_FAILED(res)) return res; + } + else if (bIsMozDiv) + { + // we are in the middle of the mozdiv: split it + PRInt32 newOffset; + res = mEditor->SplitNodeDeep( blockParent, node, offset, &newOffset); + if (NS_FAILED(res)) return res; + // put selection at beginning of new mozdiv + nsCOMPtr parent; + blockParent->GetParentNode(getter_AddRefs(parent)); + nsCOMPtr newDiv = nsEditor::GetChildAt(parent, newOffset); + if (!newDiv || !IsMozDiv(newDiv)) return NS_ERROR_FAILURE; + res = aSelection->Collapse(newDiv, 0); + if (NS_FAILED(res)) return res; + *aCancel = PR_TRUE; + } + // headers: close (or split) header - if (IsHeader(blockParent)) + else if (IsHeader(blockParent)) { res = ReturnInHeader(aSelection, blockParent, node, offset); *aCancel = PR_TRUE; @@ -328,14 +454,14 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel) } // paragraphs: special rules to look for
s - if (IsParagraph(blockParent)) + else if (IsParagraph(blockParent)) { res = ReturnInParagraph(aSelection, blockParent, node, offset, aCancel); return NS_OK; } // list items: special rules to make new list items - if (IsListItem(blockParent)) + else if (IsListItem(blockParent)) { res = ReturnInListItem(aSelection, blockParent, node, offset); *aCancel = PR_TRUE; @@ -411,10 +537,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection, nsIEditor::ESe if (!leftParent || !rightParent) return NS_OK; // bail to default - nsCOMPtr leftAtom = mEditor->GetTag(leftParent); - nsCOMPtr rightAtom = mEditor->GetTag(rightParent); - - if (leftAtom.get() == rightAtom.get()) + if (mEditor->NodesSameType(leftParent, rightParent)) { nsCOMPtr topParent; leftParent->GetParentNode(getter_AddRefs(topParent)); @@ -454,10 +577,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection, nsIEditor::ESe // are the blocks of same type? nsCOMPtr leftParent = mEditor->GetBlockNodeParent(node); nsCOMPtr rightParent = mEditor->GetBlockNodeParent(nextNode); - nsCOMPtr leftAtom = mEditor->GetTag(leftParent); - nsCOMPtr rightAtom = mEditor->GetTag(rightParent); - - if (leftAtom.get() == rightAtom.get()) + if (mEditor->NodesSameType(leftParent, rightParent)) { nsCOMPtr topParent; leftParent->GetParentNode(getter_AddRefs(topParent)); @@ -561,10 +681,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection, nsIEditor::ESe // bail to default if blocks aren't siblings if (leftBlockParent.get() != rightBlockParent.get()) return NS_OK; - nsCOMPtr leftAtom = mEditor->GetTag(leftParent); - nsCOMPtr rightAtom = mEditor->GetTag(rightParent); - - if (leftAtom.get() == rightAtom.get()) + if (mEditor->NodesSameType(leftParent, rightParent)) { nsCOMPtr topParent; leftParent->GetParentNode(getter_AddRefs(topParent)); @@ -810,8 +927,15 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection, PRBool aOrdered, PRBo } else { - nsAutoString listItemType = "li"; - res = InsertContainerAbove(curNode, &listItem, listItemType); + // don't wrap li around a moz-div. instead replace moz-div with li + if (IsMozDiv(curNode)) + { + res = ReplaceContainer(curNode, &listItem, "li"); + } + else + { + res = InsertContainerAbove(curNode, &listItem, "li"); + } if (NS_FAILED(res)) return res; if (nsEditor::IsInlineNode(curNode)) prevListItem = listItem; @@ -1291,6 +1415,7 @@ nsHTMLEditRules::IsHeader(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsHeader"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if ( (tag == "h1") || (tag == "h2") || (tag == "h3") || @@ -1313,6 +1438,7 @@ nsHTMLEditRules::IsParagraph(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsParagraph"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if (tag == "p") { return PR_TRUE; @@ -1330,6 +1456,7 @@ nsHTMLEditRules::IsListItem(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsListItem"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if (tag == "li") { return PR_TRUE; @@ -1347,6 +1474,7 @@ nsHTMLEditRules::IsList(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsList"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if ( (tag == "ol") || (tag == "ul") ) { @@ -1365,6 +1493,7 @@ nsHTMLEditRules::IsOrderedList(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsOrderedList"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if (tag == "ol") { return PR_TRUE; @@ -1382,6 +1511,7 @@ nsHTMLEditRules::IsUnorderedList(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsUnorderedList"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if (tag == "ul") { return PR_TRUE; @@ -1399,6 +1529,7 @@ nsHTMLEditRules::IsBreak(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsBreak"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if (tag == "br") { return PR_TRUE; @@ -1416,6 +1547,7 @@ nsHTMLEditRules::IsBody(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsBody"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if (tag == "body") { return PR_TRUE; @@ -1433,6 +1565,7 @@ nsHTMLEditRules::IsBlockquote(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsBlockquote"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if (tag == "blockquote") { return PR_TRUE; @@ -1441,6 +1574,24 @@ nsHTMLEditRules::IsBlockquote(nsIDOMNode *node) } +/////////////////////////////////////////////////////////////////////////// +// IsAnchor: true if node an html anchor node +// +PRBool +nsHTMLEditRules::IsAnchor(nsIDOMNode *node) +{ + NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsAnchor"); + nsAutoString tag; + nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); + if (tag == "a") + { + return PR_TRUE; + } + return PR_FALSE; +} + + /////////////////////////////////////////////////////////////////////////// // IsDiv: true if node an html div node // @@ -1450,6 +1601,7 @@ nsHTMLEditRules::IsDiv(nsIDOMNode *node) NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::IsDiv"); nsAutoString tag; nsEditor::GetTagString(node,tag); + tag.ToLowerCase(); if (tag == "div") { return PR_TRUE; @@ -1458,6 +1610,51 @@ nsHTMLEditRules::IsDiv(nsIDOMNode *node) } +/////////////////////////////////////////////////////////////////////////// +// IsNormalDiv: true if node an html div node, without type = _moz +// +PRBool +nsHTMLEditRules::IsNormalDiv(nsIDOMNode *node) +{ + if (IsDiv(node) && !HasMozAttr(node)) return PR_TRUE; + return PR_FALSE; +} + + +/////////////////////////////////////////////////////////////////////////// +// IsMozDiv: true if node an html div node with type = _moz +// +PRBool +nsHTMLEditRules::IsMozDiv(nsIDOMNode *node) +{ + if (IsDiv(node) && HasMozAttr(node)) return PR_TRUE; + return PR_FALSE; +} + + +/////////////////////////////////////////////////////////////////////////// +// HasMozAttr: true if node has type attribute = _moz +// (used to indicate the div's and br's we use in +// mail compose rules) +// +PRBool +nsHTMLEditRules::HasMozAttr(nsIDOMNode *node) +{ + NS_PRECONDITION(node, "null parent passed to nsHTMLEditRules::HasMozAttr"); + nsCOMPtr elem = do_QueryInterface(node); + if (elem) + { + nsAutoString typeAttrName("type"); + nsAutoString typeAttrVal; + nsresult res = elem->GetAttribute(typeAttrName, typeAttrVal); + typeAttrVal.ToLowerCase(); + if (NS_SUCCEEDED(res) && (typeAttrVal == "_moz")) + return PR_TRUE; + } + return PR_FALSE; +} + + /////////////////////////////////////////////////////////////////////////// // IsMailCite: true if node an html blockquote with type=cite // @@ -1471,6 +1668,7 @@ nsHTMLEditRules::IsMailCite(nsIDOMNode *node) nsAutoString typeAttrName("type"); nsAutoString typeAttrVal; nsresult res = bqElem->GetAttribute(typeAttrName, typeAttrVal); + typeAttrVal.ToLowerCase(); if (NS_SUCCEEDED(res)) { if (typeAttrVal == "cite") @@ -1544,6 +1742,17 @@ nsHTMLEditRules::IsEmptyNode(nsIDOMNode *aNode, PRBool *outIsEmptyNode) return NS_OK; } + // if it's not a text node (handled above) and it's not a container, + // then we dont call it empty (it's an


, or
, etc). + // Also, if it's an anchor then dont treat it as empty - even though + // anchors are containers, named anchors are "empty" but we don't + // want to treat them as such. + if (!mEditor->IsContainer(aNode) || IsAnchor(aNode)) + { + *outIsEmptyNode = PR_FALSE; + return NS_OK; + } + // iterate over node. if no children, or all children are either // empty text nodes or non-editable, then node qualifies as empty nsCOMPtr iter; @@ -1593,6 +1802,24 @@ nsHTMLEditRules::IsEmptyNode(nsIDOMNode *aNode, PRBool *outIsEmptyNode) } +/////////////////////////////////////////////////////////////////////////// +// CreateMozDiv: makes a div with type = _moz +// +nsresult +nsHTMLEditRules::CreateMozDiv(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr *outDiv) +{ + if (!inParent || !outDiv) return NS_ERROR_NULL_POINTER; + nsAutoString divType= "div"; + *outDiv = nsnull; + nsresult res = mEditor->CreateNode(divType, inParent, inOffset, getter_AddRefs(*outDiv)); + if (NS_FAILED(res)) return res; + // give it special moz attr + nsCOMPtr mozDivElem = do_QueryInterface(*outDiv); + res = mEditor->SetAttribute(mozDivElem, "type", "_moz"); + return res; +} + + /////////////////////////////////////////////////////////////////////////// // GetPriorHTMLNode: returns the previous editable leaf node, if there is // one within the @@ -1757,6 +1984,48 @@ nsHTMLEditRules::IsLastNode(nsIDOMNode *aNode) } +/////////////////////////////////////////////////////////////////////////// +// AtStartOfBlock: is node/offset at the start of the editable material in this block? +// +PRBool +nsHTMLEditRules::AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock) +{ + nsCOMPtr nodeAsText = do_QueryInterface(aNode); + if (nodeAsText && aOffset) return PR_FALSE; // there are chars in front of us + + nsCOMPtr priorNode; + nsresult res = GetPriorHTMLNode(aNode, aOffset, &priorNode); + if (NS_FAILED(res)) return PR_TRUE; + if (!priorNode) return PR_TRUE; + nsCOMPtr blockParent = mEditor->GetBlockNodeParent(priorNode); + if (blockParent && (blockParent.get() == aBlock)) return PR_FALSE; + return PR_TRUE; +} + + +/////////////////////////////////////////////////////////////////////////// +// AtEndOfBlock: is node/offset at the end of the editable material in this block? +// +PRBool +nsHTMLEditRules::AtEndOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock) +{ + nsCOMPtr nodeAsText = do_QueryInterface(aNode); + if (nodeAsText) + { + PRUint32 strLength; + nodeAsText->GetLength(&strLength); + if (strLength > aOffset) return PR_FALSE; // there are chars in after us + } + nsCOMPtr nextNode; + nsresult res = GetNextHTMLNode(aNode, aOffset, &nextNode); + if (NS_FAILED(res)) return PR_TRUE; + if (!nextNode) return PR_TRUE; + nsCOMPtr blockParent = mEditor->GetBlockNodeParent(nextNode); + if (blockParent && (blockParent.get() == aBlock)) return PR_FALSE; + return PR_TRUE; +} + + /////////////////////////////////////////////////////////////////////////// // GetPromotedPoint: figure out where a start or end point for a block // operation really is @@ -2171,7 +2440,7 @@ nsHTMLEditRules::RemoveContainer(nsIDOMNode *inNode) nsresult nsHTMLEditRules::InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr *outNode, - nsString &aNodeType) + const nsString &aNodeType) { if (!inNode || !outNode) return NS_ERROR_NULL_POINTER; @@ -2207,7 +2476,6 @@ nsHTMLEditRules::InsertContainerAbove(nsIDOMNode *inNode, nsresult nsHTMLEditRules::InsertTab(nsIDOMSelection *aSelection, PRBool *aCancel, - PlaceholderTxn **aTxn, nsString *outString) { nsCOMPtr parentNode; @@ -2271,7 +2539,6 @@ nsHTMLEditRules::InsertTab(nsIDOMSelection *aSelection, nsresult nsHTMLEditRules::InsertSpace(nsIDOMSelection *aSelection, PRBool *aCancel, - PlaceholderTxn **aTxn, nsString *outString) { nsCOMPtr parentNode; @@ -2351,10 +2618,6 @@ nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection, res = mEditor->SplitNodeDeep( aHeader, aNode, aOffset, &newOffset); if (NS_FAILED(res)) return res; -// revisit the below when we move to using divs as standard paragraphs. -// need to create an "empty" div in the fisrt case below, and need to -// use a div instead of a

in the second case below - // if the new (righthand) header node is empty, delete it PRBool isEmpty; res = IsEmptyBlock(aHeader, &isEmpty); @@ -2366,10 +2629,13 @@ nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection, res = aSelection->Collapse(headerParent,offset+1); return res; } - // else rewrap it in a paragraph + // else rewrap it in a mozdiv nsCOMPtr newBlock; - nsAutoString blockType("p"); - res = ReplaceContainer(aHeader,&newBlock,blockType); + res = ReplaceContainer(aHeader,&newBlock,"div"); + if (NS_FAILED(res)) return res; + // give it special moz attr + nsCOMPtr mozDivElem = do_QueryInterface(newBlock); + res = mEditor->SetAttribute(mozDivElem, "type", "_moz"); if (NS_FAILED(res)) return res; res = aSelection->Collapse(newBlock,0); return res; @@ -2685,10 +2951,11 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString // to breaks, and runs of spaces to nbsps. // xxx floppy moose - // if curNode is a p, header, address, or pre, replace + // if curNode is a mozdiv, p, header, address, or pre, replace // it with a new block of correct type. // xxx floppy moose: pre cant hold everything the others can - if ((curNodeTag == "pre") || + if (IsMozDiv(curNode) || + (curNodeTag == "pre") || (curNodeTag == "p") || (curNodeTag == "h1") || (curNodeTag == "h2") || @@ -2710,7 +2977,7 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString (curNodeTag == "ul") || (curNodeTag == "li") || (curNodeTag == "blockquote") || - (curNodeTag == "div")) + (curNodeTag == "div")) // div's other than mozdivs { curBlock = 0; // forget any previous block used for previous inline nodes // recursion time @@ -2769,24 +3036,14 @@ nsHTMLEditRules::IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst) *aOutIsFirst = PR_FALSE; // find first editable child and compare it to aNode - nsCOMPtr parent; + nsCOMPtr parent, firstChild; 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 = GetNextHTMLNode(child, &tmp); - if (NS_FAILED(res)) return res; - if (!tmp) return NS_ERROR_FAILURE; - child = tmp; - } + res = GetFirstEditableChild(parent, &firstChild); + if (NS_FAILED(res)) return res; - *aOutIsFirst = (child.get() == aNode); + *aOutIsFirst = (firstChild.get() == aNode); return res; } @@ -2801,24 +3058,70 @@ nsHTMLEditRules::IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast) *aOutIsLast = PR_FALSE; // find last editable child and compare it to aNode - nsCOMPtr parent; + nsCOMPtr parent, lastChild; 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; + res = GetLastEditableChild(parent, &lastChild); + if (NS_FAILED(res)) return res; + + *aOutIsLast = (lastChild.get() == aNode); + return res; +} - if (!mEditor->IsEditable(child)) + +nsresult +nsHTMLEditRules::GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr *aOutFirstChild) +{ + // check parms + if (!aOutFirstChild || !aNode) return NS_ERROR_NULL_POINTER; + + // init out parms + *aOutFirstChild = nsnull; + + // find first editable child + nsCOMPtr child; + nsresult res = aNode->GetFirstChild(getter_AddRefs(child)); + if (NS_FAILED(res)) return res; + + while (child && !mEditor->IsEditable(child)) { nsCOMPtr tmp; - res = GetPriorHTMLNode(child, &tmp); + res = child->GetNextSibling(getter_AddRefs(tmp)); if (NS_FAILED(res)) return res; if (!tmp) return NS_ERROR_FAILURE; child = tmp; } - *aOutIsLast = (child.get() == aNode); + *aOutFirstChild = child; + return res; +} + + +nsresult +nsHTMLEditRules::GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr *aOutLastChild) +{ + // check parms + if (!aOutLastChild || !aNode) return NS_ERROR_NULL_POINTER; + + // init out parms + *aOutLastChild = nsnull; + + // find last editable child + nsCOMPtr child; + nsresult res = aNode->GetLastChild(getter_AddRefs(child)); + if (NS_FAILED(res)) return res; + + while (child && !mEditor->IsEditable(child)) + { + nsCOMPtr tmp; + res = child->GetPreviousSibling(getter_AddRefs(tmp)); + if (NS_FAILED(res)) return res; + if (!tmp) return NS_ERROR_FAILURE; + child = tmp; + } + + *aOutLastChild = child; return res; } @@ -2843,10 +3146,21 @@ nsHTMLEditRules::JoinNodesSmart( nsIDOMNode *aNodeLeft, nsresult res = NS_OK; // caller responsible for: // left & right node are same type - // left & right node have same parent - - nsCOMPtr parent; - aNodeLeft->GetParentNode(getter_AddRefs(parent)); + PRInt32 parOffset; + nsCOMPtr parent, rightParent; + res = nsEditor::GetNodeLocation(aNodeLeft, &parent, &parOffset); + if (NS_FAILED(res)) return res; + aNodeRight->GetParentNode(getter_AddRefs(rightParent)); + + // if they don't have the same parent, first move the 'right' node + // to after the 'left' one + if (parent != rightParent) + { + res = mEditor->DeleteNode(aNodeRight); + if (NS_FAILED(res)) return res; + res = mEditor->InsertNode(aNodeRight, parent, parOffset); + if (NS_FAILED(res)) return res; + } // defaults for outParams *aOutMergeParent = aNodeRight; @@ -2891,14 +3205,23 @@ nsHTMLEditRules::JoinNodesSmart( nsIDOMNode *aNodeLeft, } else { + // remember the last left child, and firt right child + nsCOMPtr lastLeft, firstRight; + res = GetLastEditableChild(aNodeLeft, &lastLeft); + if (NS_FAILED(res)) return res; + res = GetFirstEditableChild(aNodeRight, &firstRight); + if (NS_FAILED(res)) return res; + // for list items, divs, etc, merge smart res = mEditor->JoinNodes(aNodeLeft, aNodeRight, parent); if (NS_FAILED(res)) return res; - // XXX floppy moose - figure out newNodeLeft & newNodeRight and recurse - // res = JoinNodesSmart(newNodeLeft, newNodeRight, aOutMergeParent, aOutMergeOffset); - // if (NS_FAILED(res)) return res; - return res; + + if (lastLeft && firstRight && mEditor->NodesSameType(lastLeft, firstRight)) + { + return JoinNodesSmart(lastLeft, firstRight, aOutMergeParent, aOutMergeOffset); + } } + return res; } @@ -3057,10 +3380,17 @@ nsHTMLEditRules::PopListItem(nsIDOMNode *aListItem, PRBool *aOutOfList) res = mEditor->InsertNode(curNode, curParPar, parOffset); if (NS_FAILED(res)) return res; - // remove list items container if we promoted them out of list + // change list items container to mozdiv if we promoted them out of list if (!IsList(curParPar) && IsListItem(curNode)) { - res = RemoveContainer(curNode); + nsCOMPtr mozDiv; + res = ReplaceContainer(curNode, &mozDiv, "div"); + if (NS_FAILED(res)) return res; + // give it special moz attr + nsCOMPtr mozDivElem = do_QueryInterface(mozDiv); + res = mEditor->SetAttribute(mozDivElem, "type", "_moz"); + if (NS_FAILED(res)) return res; + *aOutOfList = PR_TRUE; if (NS_FAILED(res)) return res; } diff --git a/editor/libeditor/html/nsHTMLEditRules.h b/editor/libeditor/html/nsHTMLEditRules.h index c2583c5ea8b..addb5cca447 100644 --- a/editor/libeditor/html/nsHTMLEditRules.h +++ b/editor/libeditor/html/nsHTMLEditRules.h @@ -49,7 +49,6 @@ protected: // nsHTMLEditRules implementation methods nsresult WillInsertText(nsIDOMSelection *aSelection, PRBool *aCancel, - PlaceholderTxn **aTxn, const nsString *inString, nsString *outString, TypeInState typeInState, @@ -63,8 +62,8 @@ protected: nsresult WillAlign(nsIDOMSelection *aSelection, const nsString *alignType, PRBool *aCancel); nsresult WillMakeBasicBlock(nsIDOMSelection *aSelection, const nsString *aBlockType, PRBool *aCancel); - nsresult InsertTab(nsIDOMSelection *aSelection, PRBool *aCancel, PlaceholderTxn **aTxn, nsString *outString); - nsresult InsertSpace(nsIDOMSelection *aSelection, PRBool *aCancel, PlaceholderTxn **aTxn, nsString *outString); + nsresult InsertTab(nsIDOMSelection *aSelection, PRBool *aCancel, nsString *outString); + nsresult InsertSpace(nsIDOMSelection *aSelection, PRBool *aCancel, nsString *outString); nsresult ReturnInHeader(nsIDOMSelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset); nsresult ReturnInParagraph(nsIDOMSelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset, PRBool *aCancel); @@ -83,8 +82,12 @@ protected: static PRBool IsBreak(nsIDOMNode *aNode); static PRBool IsBody(nsIDOMNode *aNode); static PRBool IsBlockquote(nsIDOMNode *aNode); + static PRBool IsAnchor(nsIDOMNode *aNode); static PRBool IsDiv(nsIDOMNode *aNode); + static PRBool IsNormalDiv(nsIDOMNode *aNode); + static PRBool IsMozDiv(nsIDOMNode *aNode); static PRBool IsMailCite(nsIDOMNode *aNode); + static PRBool HasMozAttr(nsIDOMNode *aNode); static PRBool InBody(nsIDOMNode *aNode); @@ -92,6 +95,9 @@ protected: nsresult IsEmptyNode(nsIDOMNode *aNode, PRBool *outIsEmptyNode); PRBool IsFirstNode(nsIDOMNode *aNode); PRBool IsLastNode(nsIDOMNode *aNode); + PRBool AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock); + PRBool AtEndOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock); + nsresult CreateMozDiv(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr *outDiv); nsresult GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr *outNode); nsresult GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr *outNode); nsresult GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr *outNode); @@ -115,10 +121,12 @@ protected: nsresult ReplaceContainer(nsIDOMNode *inNode, nsCOMPtr *outNode, const nsString &aNodeType); nsresult RemoveContainer(nsIDOMNode *inNode); - nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr *outNode, nsString &aNodeType); + nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr *outNode, const nsString &aNodeType); nsresult IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst); nsresult IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast); + nsresult GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr *aOutFirstChild); + nsresult GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr *aOutLastChild); nsresult JoinNodesSmart( nsIDOMNode *aNodeLeft, nsIDOMNode *aNodeRight, diff --git a/editor/libeditor/html/nsHTMLEditor.cpp b/editor/libeditor/html/nsHTMLEditor.cpp index c4eaf618c17..2012a09a449 100644 --- a/editor/libeditor/html/nsHTMLEditor.cpp +++ b/editor/libeditor/html/nsHTMLEditor.cpp @@ -64,6 +64,7 @@ #include "nsAOLCiter.h" #include "nsInternetCiter.h" #include "nsISupportsPrimitives.h" +#include "InsertTextTxn.h" // netwerk #include "nsIURI.h" @@ -89,7 +90,7 @@ const unsigned char nbsp = 160; // {a6cf9107-15b3-11d2-932e-00805f8add32} #define NS_CNAVDTD_CID \ { 0xa6cf9107, 0x15b3, 0x11d2, { 0x93, 0x2e, 0x0, 0x80, 0x5f, 0x8a, 0xdd, 0x32 } } -static NS_DEFINE_CID(kCNavDTDCID, NS_CNAVDTD_CID); +static NS_DEFINE_CID(kCNavDTDCID, NS_CNAVDTD_CID); static NS_DEFINE_CID(kHTMLEditorCID, NS_HTMLEDITOR_CID); static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID); @@ -111,6 +112,8 @@ static const PRBool gNoisy = PR_FALSE; static char hrefText[] = "href"; static char anchorTxt[] = "anchor"; static char namedanchorText[] = "namedanchor"; +nsIAtom *nsHTMLEditor::gTypingTxnName; + #define IsLink(s) (s.EqualsIgnoreCase(hrefText)) #define IsNamedAnchor(s) (s.EqualsIgnoreCase(anchorTxt) || s.EqualsIgnoreCase(namedanchorText)) @@ -206,6 +209,8 @@ nsHTMLEditor::nsHTMLEditor() { // Done in nsEditor // NS_INIT_REFCNT(); + if (!gTypingTxnName) + gTypingTxnName = NS_NewAtom("Typing"); } nsHTMLEditor::~nsHTMLEditor() @@ -214,7 +219,7 @@ nsHTMLEditor::~nsHTMLEditor() //but we need to also remove the listeners or we have a leak nsCOMPtrselection; nsresult result = GetSelection(getter_AddRefs(selection)); - // if we don't get the selection, just skip this + // if we don't get the selection, just skip this if (NS_SUCCEEDED(result) && selection) { nsCOMPtrlistener; @@ -240,16 +245,16 @@ nsHTMLEditor::~nsHTMLEditor() if (mMouseListenerP) { erP->RemoveEventListenerByIID(mMouseListenerP, nsIDOMMouseListener::GetIID()); } - if (mTextListenerP) { + if (mTextListenerP) { erP->RemoveEventListenerByIID(mTextListenerP, nsIDOMTextListener::GetIID()); - } - if (mCompositionListenerP) { - erP->RemoveEventListenerByIID(mCompositionListenerP, nsIDOMCompositionListener::GetIID()); - } + } + if (mCompositionListenerP) { + erP->RemoveEventListenerByIID(mCompositionListenerP, nsIDOMCompositionListener::GetIID()); + } if (mFocusListenerP) { erP->RemoveEventListenerByIID(mFocusListenerP, nsIDOMFocusListener::GetIID()); } - if (mDragListenerP) { + if (mDragListenerP) { erP->RemoveEventListenerByIID(mDragListenerP, nsIDOMDragListener::GetIID()); } } @@ -305,7 +310,7 @@ NS_IMETHODIMP nsHTMLEditor::Init(nsIDOMDocument *aDoc, { NS_PRECONDITION(aDoc && aPresShell, "bad arg"); if (!aDoc || !aPresShell) - return NS_ERROR_NULL_POINTER; + return NS_ERROR_NULL_POINTER; nsresult result = NS_ERROR_NULL_POINTER; // Init the base editor @@ -333,7 +338,7 @@ NS_IMETHODIMP nsHTMLEditor::Init(nsIDOMDocument *aDoc, // XXX: ERROR CHECKING should InitRules return an error, and then we could check it here? InitRules(); - EnableUndo(PR_TRUE); + EnableUndo(PR_TRUE); // Set up a DTD XXX XXX // HACK: This should have happened in a document specific way @@ -382,8 +387,8 @@ nsHTMLEditor::InstallEventListeners() #ifdef DEBUG_TAGUE printf("nsTextEditor.cpp: failed to get TextEvent Listener\n"); #endif - HandleEventListenerError(); - return result; + HandleEventListenerError(); + return result; } // get a composition listener @@ -392,8 +397,8 @@ printf("nsTextEditor.cpp: failed to get TextEvent Listener\n"); #ifdef DEBUG_TAGUE printf("nsTextEditor.cpp: failed to get TextEvent Listener\n"); #endif - HandleEventListenerError(); - return result; + HandleEventListenerError(); + return result; } // get a drag listener @@ -423,31 +428,31 @@ printf("nsTextEditor.cpp: failed to get TextEvent Listener\n"); // register the event listeners with the DOM event reveiver result = erP->AddEventListenerByIID(mKeyListenerP, nsIDOMKeyListener::GetIID()); NS_ASSERTION(NS_SUCCEEDED(result), "failed to register key listener"); - if (NS_SUCCEEDED(result)) - { - result = erP->AddEventListenerByIID(mMouseListenerP, nsIDOMMouseListener::GetIID()); - NS_ASSERTION(NS_SUCCEEDED(result), "failed to register mouse listener"); - if (NS_SUCCEEDED(result)) - { - result = erP->AddEventListenerByIID(mFocusListenerP, nsIDOMFocusListener::GetIID()); - NS_ASSERTION(NS_SUCCEEDED(result), "failed to register focus listener"); - if (NS_SUCCEEDED(result)) - { - result = erP->AddEventListenerByIID(mTextListenerP, nsIDOMTextListener::GetIID()); - NS_ASSERTION(NS_SUCCEEDED(result), "failed to register text listener"); - if (NS_SUCCEEDED(result)) - { - result = erP->AddEventListenerByIID(mCompositionListenerP, nsIDOMCompositionListener::GetIID()); - NS_ASSERTION(NS_SUCCEEDED(result), "failed to register composition listener"); - if (NS_SUCCEEDED(result)) - { - result = erP->AddEventListenerByIID(mDragListenerP, nsIDOMDragListener::GetIID()); - NS_ASSERTION(NS_SUCCEEDED(result), "failed to register drag listener"); - } - } - } - } - } + if (NS_SUCCEEDED(result)) + { + result = erP->AddEventListenerByIID(mMouseListenerP, nsIDOMMouseListener::GetIID()); + NS_ASSERTION(NS_SUCCEEDED(result), "failed to register mouse listener"); + if (NS_SUCCEEDED(result)) + { + result = erP->AddEventListenerByIID(mFocusListenerP, nsIDOMFocusListener::GetIID()); + NS_ASSERTION(NS_SUCCEEDED(result), "failed to register focus listener"); + if (NS_SUCCEEDED(result)) + { + result = erP->AddEventListenerByIID(mTextListenerP, nsIDOMTextListener::GetIID()); + NS_ASSERTION(NS_SUCCEEDED(result), "failed to register text listener"); + if (NS_SUCCEEDED(result)) + { + result = erP->AddEventListenerByIID(mCompositionListenerP, nsIDOMCompositionListener::GetIID()); + NS_ASSERTION(NS_SUCCEEDED(result), "failed to register composition listener"); + if (NS_SUCCEEDED(result)) + { + result = erP->AddEventListenerByIID(mDragListenerP, nsIDOMDragListener::GetIID()); + NS_ASSERTION(NS_SUCCEEDED(result), "failed to register drag listener"); + } + } + } + } + } if (NS_FAILED(result)) { HandleEventListenerError(); } @@ -475,9 +480,9 @@ void nsHTMLEditor::InitRules() // instantiate the rules for this text editor // XXX: we should be told which set of rules to instantiate if (mFlags & eEditorPlaintextMask) - mRules = new nsTextEditRules(); - else - mRules = new nsHTMLEditRules(); + mRules = new nsTextEditRules(); + else + mRules = new nsHTMLEditRules(); mRules->Init(this, mFlags); } @@ -493,6 +498,8 @@ NS_IMETHODIMP nsHTMLEditor::EditorKeyPress(nsIDOMUIEvent* aKeyEvent) PRUint32 keyCode, character; PRBool isShift, ctrlKey, altKey, metaKey; nsresult res; + + nsAutoPlaceHolderBatch batch(this, gTypingTxnName); if (!aKeyEvent) return NS_ERROR_NULL_POINTER; @@ -518,7 +525,10 @@ NS_IMETHODIMP nsHTMLEditor::EditorKeyPress(nsIDOMUIEvent* aKeyEvent) else if (keyCode == nsIDOMUIEvent::DOM_VK_RETURN) { if (isShift && !(mFlags&eEditorPlaintextBit)) - return InsertBR(); // only inserts a br node + { + nsCOMPtr brNode; + return InsertBR(&brNode); // only inserts a br node + } else return InsertBreak(); // uses rules to figure out what to insert } @@ -595,11 +605,13 @@ NS_IMETHODIMP nsHTMLEditor::TabInTable(PRBool inIsShift, PRBool *outHandled) return NS_OK; } -NS_IMETHODIMP nsHTMLEditor::InsertBR() +NS_IMETHODIMP nsHTMLEditor::InsertBR(nsCOMPtr *outBRNode) { PRBool bCollapsed; nsCOMPtr selection; + if (!outBRNode) return NS_ERROR_NULL_POINTER; + *outBRNode = nsnull; nsresult res = GetSelection(getter_AddRefs(selection)); if (NS_FAILED(res)) return res; res = selection->GetIsCollapsed(&bCollapsed); @@ -640,6 +652,7 @@ NS_IMETHODIMP nsHTMLEditor::InsertBR() if (NS_FAILED(res)) return res; } + *outBRNode = brNode; return NS_OK; } @@ -650,6 +663,8 @@ NS_IMETHODIMP nsHTMLEditor::SetInlineProperty(nsIAtom *aProperty, if (!aProperty) { return NS_ERROR_NULL_POINTER; } if (!mRules) { return NS_ERROR_NOT_INITIALIZED; } + nsAutoEditBatch batchIt(this); + if (gNoisy) { nsAutoString propString; @@ -679,7 +694,6 @@ NS_IMETHODIMP nsHTMLEditor::SetInlineProperty(nsIAtom *aProperty, else { // set the text property for all selected ranges - nsEditor::BeginTransaction(); nsCOMPtr enumerator; result = selection->GetEnumerator(getter_AddRefs(enumerator)); if (NS_FAILED(result)) return result; @@ -761,7 +775,6 @@ NS_IMETHODIMP nsHTMLEditor::SetInlineProperty(nsIAtom *aProperty, // XXX: I'm blocked here because nsIDOMSelection doesn't provide a mechanism // for setting a compound selection yet. } - nsEditor::EndTransaction(); } // post-process result = mRules->DidDoAction(selection, &ruleInfo, result); @@ -816,7 +829,7 @@ NS_IMETHODIMP nsHTMLEditor::GetInlineProperty(nsIAtom *aProperty, nsCOMPtr currentItem; result = enumerator->CurrentItem(getter_AddRefs(currentItem)); // XXX: should be a while loop, to get each separate range - // XXX: ERROR_HANDLING can currentItem be null? + // XXX: ERROR_HANDLING can currentItem be null? if ((NS_SUCCEEDED(result)) && currentItem) { PRBool firstNodeInRange = PR_TRUE; // for each range, set a flag @@ -904,6 +917,8 @@ NS_IMETHODIMP nsHTMLEditor::RemoveInlineProperty(nsIAtom *aProperty, const nsStr if (!aProperty) { return NS_ERROR_NULL_POINTER; } if (!mRules) { return NS_ERROR_NOT_INITIALIZED; } + nsAutoEditBatch batchIt(this); + if (gNoisy) { nsAutoString propString; @@ -941,7 +956,6 @@ NS_IMETHODIMP nsHTMLEditor::RemoveInlineProperty(nsIAtom *aProperty, const nsStr PRInt32 rangeStartOffset, rangeEndOffset; GetTextSelectionOffsetsForRange(selection, getter_AddRefs(parentForSelection), rangeStartOffset, rangeEndOffset); - nsEditor::BeginTransaction(); nsCOMPtr startParent, endParent; PRInt32 startOffset, endOffset; nsCOMPtr enumerator; @@ -959,17 +973,17 @@ NS_IMETHODIMP nsHTMLEditor::RemoveInlineProperty(nsIAtom *aProperty, const nsStr nsCOMPtr range( do_QueryInterface(currentItem) ); nsCOMPtrcommonParent; result = range->GetCommonParent(getter_AddRefs(commonParent)); - if (NS_FAILED(result)) return result; - if (!commonParent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!commonParent) return NS_ERROR_NULL_POINTER; range->GetStartOffset(&startOffset); range->GetEndOffset(&endOffset); result = range->GetStartParent(getter_AddRefs(startParent)); - if (NS_FAILED(result)) return result; - if (!startParent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!startParent) return NS_ERROR_NULL_POINTER; result = range->GetEndParent(getter_AddRefs(endParent)); - if (NS_FAILED(result)) return result; - if (!endParent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!endParent) return NS_ERROR_NULL_POINTER; if (startParent.get()==endParent.get()) { // the range is entirely contained within a single text node @@ -996,14 +1010,13 @@ NS_IMETHODIMP nsHTMLEditor::RemoveInlineProperty(nsIAtom *aProperty, const nsStr // for setting a compound selection yet. } } - if (NS_SUCCEEDED(result)) - { - result = CollapseAdjacentTextNodes(selection); // we may have created wasteful consecutive text nodes. collapse them. - } - nsEditor::EndTransaction(); + if (NS_SUCCEEDED(result)) + { + result = CollapseAdjacentTextNodes(selection); // we may have created wasteful consecutive text nodes. collapse them. + } if (NS_SUCCEEDED(result)) { - // XXX: ERROR_HANDLING should get a result and validate it + // XXX: ERROR_HANDLING should get a result and validate it ResetTextSelectionForRange(parentForSelection, rangeStartOffset, rangeEndOffset, selection); } } @@ -1066,11 +1079,15 @@ NS_IMETHODIMP nsHTMLEditor::DeleteSelection(nsIEditor::ESelectionCollapseDirecti nsCOMPtr selection; PRBool cancel= PR_FALSE; - nsresult result = nsEditor::BeginTransaction(); - if (NS_FAILED(result)) { return result; } + // unnamed placeholder txns dont merge, but they do get sucked + // into placeholders that they are nested in. So this delte wont + // merge with other deletes, but if it happens in the course of + // a typing placehilder context, it will be consumed by that. + // This is the desired behavior. + nsAutoPlaceHolderBatch batch(this, nsnull); // pre-process - result = GetSelection(getter_AddRefs(selection)); + nsresult result = GetSelection(getter_AddRefs(selection)); if (NS_FAILED(result)) return result; if (!selection) return NS_ERROR_NULL_POINTER; @@ -1084,10 +1101,6 @@ NS_IMETHODIMP nsHTMLEditor::DeleteSelection(nsIEditor::ESelectionCollapseDirecti result = mRules->DidDoAction(selection, &ruleInfo, result); } - // XXX: ERROR_HANDLING is there any reason to not consider this a serious error? - nsresult endTxnResult = nsEditor::EndTransaction(); // don't return this result! - NS_ASSERTION ((NS_SUCCEEDED(endTxnResult)), "bad end transaction result"); - return result; } @@ -1105,7 +1118,7 @@ NS_IMETHODIMP nsHTMLEditor::InsertText(const nsString& aStringToInsert) nsAutoString resultString; PlaceholderTxn *placeholderTxn=nsnull; nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertText); - ruleInfo.placeTxn = &placeholderTxn; +// ruleInfo.placeTxn = &placeholderTxn; ruleInfo.inString = &aStringToInsert; ruleInfo.outString = &resultString; ruleInfo.typeInState = *mTypeInState; @@ -1118,8 +1131,8 @@ NS_IMETHODIMP nsHTMLEditor::InsertText(const nsString& aStringToInsert) // post-process result = mRules->DidDoAction(selection, &ruleInfo, result); } - if (placeholderTxn) - placeholderTxn->SetAbsorb(PR_FALSE); // this ends the merging of txns into placeholderTxn +// if (placeholderTxn) +// placeholderTxn->SetAbsorb(PR_FALSE); // this ends the merging of txns into placeholderTxn return result; } @@ -1219,8 +1232,6 @@ NS_IMETHODIMP nsHTMLEditor::InsertBreak() nsCOMPtr selection; PRBool cancel= PR_FALSE; - nsAutoEditBatch beginBatching(this); - // pre-process res = GetSelection(getter_AddRefs(selection)); if (NS_FAILED(res)) return res; @@ -1295,6 +1306,8 @@ nsHTMLEditor::InsertElement(nsIDOMElement* aElement, PRBool aDeleteSelection) if (!aElement) return NS_ERROR_NULL_POINTER; + nsAutoEditBatch beginBatching(this); + nsCOMPtrselection; res = GetSelection(getter_AddRefs(selection)); if (!NS_SUCCEEDED(res) || !selection) @@ -1307,8 +1320,6 @@ nsHTMLEditor::InsertElement(nsIDOMElement* aElement, PRBool aDeleteSelection) res = mRules->WillDoAction(selection, &ruleInfo, &cancel); if (cancel || (NS_FAILED(res))) return res; - nsAutoEditBatch beginBatching(this); - if (aDeleteSelection) { nsCOMPtr tempNode; @@ -1337,7 +1348,7 @@ nsHTMLEditor::InsertElement(nsIDOMElement* aElement, PRBool aDeleteSelection) nsCOMPtr parentSelectedNode; PRInt32 offsetForInsert; res = selection->GetAnchorNode(getter_AddRefs(parentSelectedNode)); - // XXX: ERROR_HANDLING bad XPCOM usage + // XXX: ERROR_HANDLING bad XPCOM usage if (NS_SUCCEEDED(res) && NS_SUCCEEDED(selection->GetAnchorOffset(&offsetForInsert)) && parentSelectedNode) { #ifdef DEBUG_cmanske @@ -1427,8 +1438,8 @@ nsHTMLEditor::DeleteSelectionAndCreateNode(const nsString& aTag, // we want the selection to be just after the new node nsCOMPtr selection; result = GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(result)) return result; - if (!selection) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!selection) return NS_ERROR_NULL_POINTER; result = selection->Collapse(parentSelectedNode, offsetOfNewNode+1); return result; @@ -1444,8 +1455,8 @@ nsHTMLEditor::SelectElement(nsIDOMElement* aElement) { nsCOMPtr selection; res = GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(res)) return res; - if (!selection) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!selection) return NS_ERROR_NULL_POINTER; nsCOMPtrparent; res = aElement->GetParentNode(getter_AddRefs(parent)); if (NS_SUCCEEDED(res) && parent) @@ -1457,10 +1468,10 @@ nsHTMLEditor::SelectElement(nsIDOMElement* aElement) { // Collapse selection to just before desired element, res = selection->Collapse(parent, offsetInParent); - if (NS_SUCCEEDED(res)) { - // then extend it to just after - res = selection->Extend(parent, offsetInParent+1); - } + if (NS_SUCCEEDED(res)) { + // then extend it to just after + res = selection->Extend(parent, offsetInParent+1); + } } } } @@ -1477,12 +1488,12 @@ nsHTMLEditor::SetCaretAfterElement(nsIDOMElement* aElement) { nsCOMPtr selection; res = GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(res)) return res; - if (!selection) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!selection) return NS_ERROR_NULL_POINTER; nsCOMPtrparent; res = aElement->GetParentNode(getter_AddRefs(parent)); - if (NS_FAILED(res)) return res; - if (!parent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!parent) return NS_ERROR_NULL_POINTER; PRInt32 offsetInParent; res = GetChildOffset(aElement, parent, offsetInParent); if (NS_SUCCEEDED(res)) @@ -1646,7 +1657,7 @@ nsHTMLEditor::AddBlockParent(nsString& aParentTag) enumerator->First(); nsCOMPtr currentItem; res = enumerator->CurrentItem(getter_AddRefs(currentItem)); - // XXX: ERROR_HANDLING can currentItem be null? + // XXX: ERROR_HANDLING can currentItem be null? if ((NS_SUCCEEDED(res)) && (currentItem)) { nsCOMPtr range( do_QueryInterface(currentItem) ); @@ -1692,7 +1703,7 @@ nsHTMLEditor::ReplaceBlockParent(nsString& aParentTag) enumerator->First(); nsCOMPtr currentItem; res = enumerator->CurrentItem(getter_AddRefs(currentItem)); - // XXX: ERROR_HANDLING can currentItem be null? + // XXX: ERROR_HANDLING can currentItem be null? if ((NS_SUCCEEDED(res)) && (currentItem)) { nsCOMPtr range( do_QueryInterface(currentItem) ); @@ -1729,7 +1740,7 @@ nsHTMLEditor::RemoveParagraphStyle() enumerator->First(); nsCOMPtr currentItem; res = enumerator->CurrentItem(getter_AddRefs(currentItem)); - // XXX: ERROR_HANDLING can currentItem be null? + // XXX: ERROR_HANDLING can currentItem be null? if ((NS_SUCCEEDED(res)) && (currentItem)) { nsCOMPtr range( do_QueryInterface(currentItem) ); @@ -1761,7 +1772,7 @@ nsHTMLEditor::RemoveParent(const nsString &aParentTag) enumerator->First(); nsCOMPtr currentItem; res = enumerator->CurrentItem(getter_AddRefs(currentItem)); - // XXX: ERROR_HANDLING can currentItem be null? + // XXX: ERROR_HANDLING can currentItem be null? if ((NS_SUCCEEDED(res)) && (currentItem)) { nsCOMPtr range( do_QueryInterface(currentItem) ); @@ -2134,7 +2145,7 @@ NODE_FOUND: } // Search up the parent chain // We should never fail because of root test below, but lets be safe - // XXX: ERROR_HANDLING error return code lost + // XXX: ERROR_HANDLING error return code lost if (!NS_SUCCEEDED(currentNode->GetParentNode(getter_AddRefs(parent))) || !parent) break; @@ -2198,14 +2209,14 @@ nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aRetu // included a collapsed selection (just a caret in a link) nsCOMPtr anchorNode; res = selection->GetAnchorNode(getter_AddRefs(anchorNode)); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; PRInt32 anchorOffset = -1; if (anchorNode) selection->GetAnchorOffset(&anchorOffset); nsCOMPtr focusNode; res = selection->GetFocusNode(getter_AddRefs(focusNode)); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; PRInt32 focusOffset = -1; if (focusNode) selection->GetFocusOffset(&focusOffset); @@ -2228,7 +2239,7 @@ nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aRetu #endif nsCOMPtr parentLinkOfAnchor; res = GetElementOrParentByTagName("href", anchorNode, getter_AddRefs(parentLinkOfAnchor)); - // XXX: ERROR_HANDLING can parentLinkOfAnchor be null? + // XXX: ERROR_HANDLING can parentLinkOfAnchor be null? if (NS_SUCCEEDED(res) && parentLinkOfAnchor) { if (isCollapsed) @@ -2268,7 +2279,7 @@ nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aRetu { nsCOMPtr enumerator; res = selection->GetEnumerator(getter_AddRefs(enumerator)); - // XXX: ERROR_HANDLING unclear what to do here, should an error just be returned if enumerator is null or res failed? + // XXX: ERROR_HANDLING unclear what to do here, should an error just be returned if enumerator is null or res failed? if (NS_SUCCEEDED(res) && enumerator) { enumerator->First(); @@ -2281,7 +2292,7 @@ nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aRetu res = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull, nsIContentIterator::GetIID(), getter_AddRefs(iter)); - // XXX: ERROR_HANDLING XPCOM usage + // XXX: ERROR_HANDLING XPCOM usage if ((NS_SUCCEEDED(res)) && iter) { iter->Init(range); @@ -2423,8 +2434,8 @@ nsHTMLEditor::CreateElementWithDefaults(const nsString& aTagName, nsIDOMElement* space += nbsp; // If we fail here, we return NS_OK anyway, since we have an OK cell node nsresult result = doc->CreateTextNode(space, getter_AddRefs(newTextNode)); - if (NS_FAILED(result)) return result; - if (!newTextNode) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!newTextNode) return NS_ERROR_NULL_POINTER; nsCOMPtrresultNode; result = newCellNode->AppendChild(newTextNode, getter_AddRefs(resultNode)); @@ -2448,7 +2459,7 @@ nsHTMLEditor::InsertLinkAroundSelection(nsIDOMElement* aAnchorElement) // DON'T RETURN EXCEPT AT THE END -- WE NEED TO RELEASE THE aAnchorElement if (!aAnchorElement) - goto DELETE_ANCHOR; // DON'T USE GOTO IN C++! + goto DELETE_ANCHOR; // DON'T USE GOTO IN C++! // We must have a real selection res = GetSelection(getter_AddRefs(selection)); @@ -2474,7 +2485,7 @@ nsHTMLEditor::InsertLinkAroundSelection(nsIDOMElement* aAnchorElement) if (anchor) { nsAutoString href; - // XXX: ERROR_HANDLING return code lost + // XXX: ERROR_HANDLING return code lost if (NS_SUCCEEDED(anchor->GetHref(href)) && href.GetUnicode() && href.Length() > 0) { nsAutoEditBatch beginBatching(this); @@ -2671,38 +2682,38 @@ NS_IMETHODIMP nsHTMLEditor::GetMaxTextLength(PRInt32& aMaxTextLength) NS_IMETHODIMP nsHTMLEditor::AddStyleSheet(nsICSSStyleSheet* aSheet) { - AddStyleSheetTxn* txn; - nsresult rv = CreateTxnForAddStyleSheet(aSheet, &txn); + AddStyleSheetTxn* txn; + nsresult rv = CreateTxnForAddStyleSheet(aSheet, &txn); if (!txn) rv = NS_ERROR_NULL_POINTER; - if (NS_SUCCEEDED(rv)) - { - rv = Do(txn); - if (NS_SUCCEEDED(rv)) - { - mLastStyleSheet = do_QueryInterface(aSheet); // save it so we can remove before applying the next one - } - } - - return rv; + if (NS_SUCCEEDED(rv)) + { + rv = Do(txn); + if (NS_SUCCEEDED(rv)) + { + mLastStyleSheet = do_QueryInterface(aSheet); // save it so we can remove before applying the next one + } + } + + return rv; } NS_IMETHODIMP nsHTMLEditor::RemoveStyleSheet(nsICSSStyleSheet* aSheet) { - RemoveStyleSheetTxn* txn; - nsresult rv = CreateTxnForRemoveStyleSheet(aSheet, &txn); + RemoveStyleSheetTxn* txn; + nsresult rv = CreateTxnForRemoveStyleSheet(aSheet, &txn); if (!txn) rv = NS_ERROR_NULL_POINTER; - if (NS_SUCCEEDED(rv)) - { - rv = Do(txn); - if (NS_SUCCEEDED(rv)) - { - mLastStyleSheet = nsnull; // forget it - } - } - - return rv; + if (NS_SUCCEEDED(rv)) + { + rv = Do(txn); + if (NS_SUCCEEDED(rv)) + { + mLastStyleSheet = nsnull; // forget it + } + } + + return rv; } @@ -3406,7 +3417,7 @@ NS_IMETHODIMP nsHTMLEditor::OutputToString(nsString& aOutputString, if (NS_SUCCEEDED(rv) && selection) encoder->SetSelection(selection); } - + // Set the wrap column. If our wrap column is 0, // i.e. wrap to body width, then don't set it, let the // document encoder use its own default. @@ -3492,7 +3503,7 @@ NS_IMETHODIMP nsHTMLEditor::OutputToStream(nsIOutputStream* aOutputStream, if (NS_SUCCEEDED(rv) && selection) encoder->SetSelection(selection); } - + // Set the wrap column. If our wrap column is 0, // i.e. wrap to body width, then don't set it, let the // document encoder use its own default. @@ -3522,10 +3533,10 @@ nsHTMLEditor::DebugUnitTests(PRInt32 *outNumTests, PRInt32 *outNumTestsFailed) if (!outNumTests || !outNumTestsFailed) return NS_ERROR_NULL_POINTER; - TextEditorTest *tester = new TextEditorTest(); - if (!tester) - return NS_ERROR_OUT_OF_MEMORY; - + TextEditorTest *tester = new TextEditorTest(); + if (!tester) + return NS_ERROR_OUT_OF_MEMORY; + tester->Run(this, outNumTests, outNumTestsFailed); delete tester; return NS_OK; @@ -3579,7 +3590,7 @@ nsHTMLEditor::ReplaceStyleSheet(nsICSSStyleSheet *aNewSheet) { nsresult rv = NS_OK; - BeginTransaction(); + nsAutoEditBatch batchIt(this); if (mLastStyleSheet) { @@ -3589,8 +3600,6 @@ nsHTMLEditor::ReplaceStyleSheet(nsICSSStyleSheet *aNewSheet) rv = AddStyleSheet(aNewSheet); - EndTransaction(); - return rv; } @@ -3721,7 +3730,7 @@ void nsHTMLEditor::IsTextPropertySetByContent(nsIDOMNode *aNode, aProperty->ToString(propName); nsCOMPtrparent; result = aNode->GetParentNode(getter_AddRefs(parent)); - if (NS_FAILED(result)) return; + if (NS_FAILED(result)) return; while (parent) { nsCOMPtrelement; @@ -3796,7 +3805,7 @@ nsresult nsHTMLEditor::GetTextSelectionOffsets(nsIDOMSelection *aSelection, PRInt32 &aOutStartOffset, PRInt32 &aOutEndOffset) { - if(!aSelection) { return NS_ERROR_NULL_POINTER; } + if(!aSelection) { return NS_ERROR_NULL_POINTER; } nsresult result; // initialize out params aOutStartOffset = 0; // default to first char in selection @@ -3811,8 +3820,8 @@ nsresult nsHTMLEditor::GetTextSelectionOffsets(nsIDOMSelection *aSelection, nsCOMPtr enumerator; result = aSelection->GetEnumerator(getter_AddRefs(enumerator)); - if (NS_FAILED(result)) return result; - if (!enumerator) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!enumerator) return NS_ERROR_NULL_POINTER; // don't use "result" in this block enumerator->First(); @@ -3845,7 +3854,7 @@ nsresult nsHTMLEditor::GetAbsoluteOffsetsForPoints(nsIDOMNode *aInStartNode, PRInt32 &aOutStartOffset, PRInt32 &aOutEndOffset) { - if(!aInStartNode || !aInEndNode || !aInCommonParentNode) { return NS_ERROR_NULL_POINTER; } + if(!aInStartNode || !aInEndNode || !aInCommonParentNode) { return NS_ERROR_NULL_POINTER; } nsresult result; // initialize out params @@ -3915,8 +3924,8 @@ nsHTMLEditor::GetTextSelectionOffsetsForRange(nsIDOMSelection *aSelection, PRInt32 &aOutStartOffset, PRInt32 &aEndOffset) { - if (!aSelection) { return NS_ERROR_NULL_POINTER; } - aOutStartOffset = aEndOffset = 0; + if (!aSelection) { return NS_ERROR_NULL_POINTER; } + aOutStartOffset = aEndOffset = 0; nsresult result; nsCOMPtr startNode, endNode; @@ -3928,8 +3937,8 @@ nsHTMLEditor::GetTextSelectionOffsetsForRange(nsIDOMSelection *aSelection, nsCOMPtr enumerator; result = aSelection->GetEnumerator(getter_AddRefs(enumerator)); - if (NS_FAILED(result)) return result; - if (!enumerator) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!enumerator) return NS_ERROR_NULL_POINTER; enumerator->First(); nsCOMPtr currentItem; result = enumerator->CurrentItem(getter_AddRefs(currentItem)); @@ -3943,8 +3952,8 @@ nsHTMLEditor::GetTextSelectionOffsetsForRange(nsIDOMSelection *aSelection, 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; @@ -3975,7 +3984,7 @@ nsHTMLEditor::GetTextSelectionOffsetsForRange(nsIDOMSelection *aSelection, iter->Next(); iter->CurrentNode(getter_AddRefs(content)); } - return result; + return result; } void nsHTMLEditor::ResetTextSelectionForRange(nsIDOMNode *aParent, @@ -3983,7 +3992,7 @@ void nsHTMLEditor::ResetTextSelectionForRange(nsIDOMNode *aParent, PRInt32 aEndOffset, nsIDOMSelection *aSelection) { - if (!aParent || !aSelection) { return; } // XXX: should return an error + if (!aParent || !aSelection) { return; } // XXX: should return an error nsCOMPtr startNode, endNode; PRInt32 startOffset, endOffset; @@ -3992,8 +4001,8 @@ void nsHTMLEditor::ResetTextSelectionForRange(nsIDOMNode *aParent, result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull, nsIContentIterator::GetIID(), getter_AddRefs(iter)); - if (NS_FAILED(result)) return; - if (!iter) return; + if (NS_FAILED(result)) return; + if (!iter) return; PRBool setStart = PR_FALSE; PRUint32 totalLength=0; nsCOMPtrtextNode; @@ -4025,7 +4034,7 @@ void nsHTMLEditor::ResetTextSelectionForRange(nsIDOMNode *aParent, } iter->Next(); iter->CurrentNode(getter_AddRefs(content)); - } + } aSelection->Collapse(startNode, startOffset); aSelection->Extend(endNode, endOffset); } @@ -4123,7 +4132,7 @@ nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode, if (((eReplaceParent==aTransformation) && (PR_FALSE==parentTag.EqualsIgnoreCase(aParentTag))) || (eInsertParent==aTransformation)) { - if (gNoisy) { DebugDumpContent(); } // DEBUG + if (gNoisy) { DebugDumpContent(); } // DEBUG res = ReParentBlockContent(nodeToReParent, aParentTag, blockParentNode, parentTag, aTransformation, getter_AddRefs(newParentNode)); if ((NS_SUCCEEDED(res)) && (newParentNode) && (eReplaceParent==aTransformation)) @@ -4165,7 +4174,7 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, PRBool removeBreakAfter = PR_FALSE; nsCOMPtrancestor; nsresult res = aNode->GetParentNode(getter_AddRefs(ancestor)); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; nsCOMPtrpreviousAncestor = do_QueryInterface(aNode); while (ancestor) { @@ -4178,15 +4187,15 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, } previousAncestor = do_QueryInterface(ancestor); res = ancestorElement->GetParentNode(getter_AddRefs(ancestor)); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; } // now, previousAncestor is the node we are operating on nsCOMPtrleftNode, rightNode; res = GetBlockSection(previousAncestor, getter_AddRefs(leftNode), getter_AddRefs(rightNode)); - if (NS_FAILED(res)) return res; - if (!leftNode || !rightNode) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!leftNode || !rightNode) return NS_ERROR_NULL_POINTER; // determine some state for managing
s around the new block PRBool isSubordinateBlock = PR_FALSE; // if true, the content is already in a subordinate block @@ -4219,8 +4228,8 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, { nsCOMPtr grandParent; res = blockParentNode->GetParentNode(getter_AddRefs(grandParent)); - if (NS_FAILED(res)) return res; - if (!grandParent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!grandParent) return NS_ERROR_NULL_POINTER; nsCOMPtrfirstChildNode, lastChildNode; blockParentNode->GetFirstChild(getter_AddRefs(firstChildNode)); blockParentNode->GetLastChild(getter_AddRefs(lastChildNode)); @@ -4364,13 +4373,13 @@ nsHTMLEditor::ReParentContentOfRange(nsIDOMRange *aRange, nsresult res; nsISupportsArray *blockSections; res = NS_NewISupportsArray(&blockSections); - if (NS_FAILED(res)) return res; - if (!blockSections) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!blockSections) return NS_ERROR_NULL_POINTER; res = GetBlockSectionsForRange(aRange, blockSections); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; - // no embedded returns allowed below here in this method, or you'll get a space leak + // no embedded returns allowed below here in this method, or you'll get a space leak nsIDOMRange *subRange; subRange = (nsIDOMRange *)(blockSections->ElementAt(0)); while (subRange) @@ -4383,10 +4392,10 @@ nsHTMLEditor::ReParentContentOfRange(nsIDOMRange *aRange, res = ReParentContentOfNode(startParent, aParentTag, aTranformation); } NS_RELEASE(subRange); - if (NS_FAILED(res)) - { // be sure to break after free of subRange - break; - } + if (NS_FAILED(res)) + { // be sure to break after free of subRange + break; + } blockSections->RemoveElementAt(0); subRange = (nsIDOMRange *)(blockSections->ElementAt(0)); } @@ -4404,21 +4413,21 @@ nsHTMLEditor::RemoveParagraphStyleFromRange(nsIDOMRange *aRange) nsISupportsArray *blockSections; res = NS_NewISupportsArray(&blockSections); if (NS_FAILED(res)) return res; - if (!blockSections) return NS_ERROR_NULL_POINTER; + if (!blockSections) return NS_ERROR_NULL_POINTER; res = GetBlockSectionsForRange(aRange, blockSections); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; - nsIDOMRange *subRange; + nsIDOMRange *subRange; subRange = (nsIDOMRange *)(blockSections->ElementAt(0)); while (subRange) { res = RemoveParagraphStyleFromBlockContent(subRange); NS_RELEASE(subRange); - if (NS_FAILED(res)) - { // be sure to break after subrange is released - break; - } + if (NS_FAILED(res)) + { // be sure to break after subrange is released + break; + } blockSections->RemoveElementAt(0); subRange = (nsIDOMRange *)(blockSections->ElementAt(0)); } @@ -4436,7 +4445,7 @@ nsHTMLEditor::RemoveParagraphStyleFromBlockContent(nsIDOMRange *aRange) aRange->GetStartParent(getter_AddRefs(startParent)); nsCOMPtrblockParentElement; res = GetBlockParent(startParent, getter_AddRefs(blockParentElement)); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; while (blockParentElement) { @@ -4456,8 +4465,8 @@ nsHTMLEditor::RemoveParagraphStyleFromBlockContent(nsIDOMRange *aRange) { nsCOMPtrgrandParent; blockParentElement->GetParentNode(getter_AddRefs(grandParent)); - if (NS_FAILED(res)) return res; - if (!grandParent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!grandParent) return NS_ERROR_NULL_POINTER; PRInt32 offsetInParent; res = GetChildOffset(blockParentElement, grandParent, offsetInParent); @@ -4472,21 +4481,21 @@ nsHTMLEditor::RemoveParagraphStyleFromBlockContent(nsIDOMRange *aRange) { res = DeleteNode(childNode); if (NS_SUCCEEDED(res)) - { + { res = InsertNode(childNode, grandParent, offsetInParent); - if (NS_FAILED(res)) return res; - } + if (NS_FAILED(res)) return res; + } } } if (NS_SUCCEEDED(res)) - { + { res = DeleteNode(blockParentElement); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; } } } res = GetBlockParent(startParent, getter_AddRefs(blockParentElement)); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; } return res; } @@ -4499,8 +4508,8 @@ nsHTMLEditor::RemoveParentFromRange(const nsString &aParentTag, nsIDOMRange *aRa nsresult res; nsISupportsArray *blockSections; res = NS_NewISupportsArray(&blockSections); - if (NS_FAILED(res)) return res; - if (!blockSections) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!blockSections) return NS_ERROR_NULL_POINTER; res = GetBlockSectionsForRange(aRange, blockSections); if (NS_SUCCEEDED(res)) { @@ -4510,10 +4519,10 @@ nsHTMLEditor::RemoveParentFromRange(const nsString &aParentTag, nsIDOMRange *aRa { res = RemoveParentFromBlockContent(aParentTag, subRange); NS_RELEASE(subRange); - if (NS_FAILED(res)) - { - break; - } + if (NS_FAILED(res)) + { + break; + } blockSections->RemoveElementAt(0); subRange = (nsIDOMRange *)(blockSections->ElementAt(0)); } @@ -4530,13 +4539,13 @@ nsHTMLEditor::RemoveParentFromBlockContent(const nsString &aParentTag, nsIDOMRan nsresult res; nsCOMPtrstartParent; res = aRange->GetStartParent(getter_AddRefs(startParent)); - if (NS_FAILED(res)) return res; - if (!startParent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!startParent) return NS_ERROR_NULL_POINTER; nsCOMPtrparentNode; nsCOMPtrparentElement; res = startParent->GetParentNode(getter_AddRefs(parentNode)); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; while (parentNode) { @@ -4550,8 +4559,8 @@ nsHTMLEditor::RemoveParentFromBlockContent(const nsString &aParentTag, nsIDOMRan // go through list backwards so deletes don't interfere with the iteration nsCOMPtr childNodes; res = parentElement->GetChildNodes(getter_AddRefs(childNodes)); - if (NS_FAILED(res)) return res; - if (!childNodes) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!childNodes) return NS_ERROR_NULL_POINTER; nsCOMPtrgrandParent; parentElement->GetParentNode(getter_AddRefs(grandParent)); @@ -4571,7 +4580,7 @@ nsHTMLEditor::RemoveParentFromBlockContent(const nsString &aParentTag, nsIDOMRan res = DeleteNode(childNode); if (NS_FAILED(res)) return res; res = InsertNode(childNode, grandParent, offsetInParent); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; } res = DeleteNode(parentElement); if (NS_FAILED(res)) { return res; } @@ -4582,7 +4591,7 @@ nsHTMLEditor::RemoveParentFromBlockContent(const nsString &aParentTag, nsIDOMRan break; } res = parentElement->GetParentNode(getter_AddRefs(parentNode)); - if (NS_FAILED(res)) return res; + if (NS_FAILED(res)) return res; } return res; } @@ -4595,8 +4604,8 @@ PRBool nsHTMLEditor::IsElementInBody(nsIDOMElement* aElement) { nsIDOMElement* bodyElement = nsnull; nsresult res = nsEditor::GetBodyElement(&bodyElement); - if (NS_FAILED(res)) return res; - if (!bodyElement) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(res)) return res; + if (!bodyElement) return NS_ERROR_NULL_POINTER; nsCOMPtr parent; nsCOMPtr currentElement = do_QueryInterface(aElement); if (currentElement) @@ -4825,8 +4834,8 @@ nsHTMLEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr &parent nsresult result=NS_ERROR_NOT_INITIALIZED; nsCOMPtr selection; result = GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(result)) return result; - if (!selection) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!selection) return NS_ERROR_NULL_POINTER; PRBool collapsed; result = selection->GetIsCollapsed(&collapsed); @@ -5058,8 +5067,8 @@ nsHTMLEditor::SetTextPropertiesForNode(nsIDOMNode *aNode, { nsCOMPtrnewStyleNode; result = nsEditor::CreateNode(tag, aParent, 0, getter_AddRefs(newStyleNode)); - if (NS_FAILED(result)) return result; - if (!newStyleNode) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!newStyleNode) return NS_ERROR_NULL_POINTER; nsCOMPtrnodeAsChar; nodeAsChar = do_QueryInterface(aNode); @@ -5201,8 +5210,8 @@ NS_IMETHODIMP nsHTMLEditor::MoveContentOfNodeIntoNewParent(nsIDOMNode *aNode, // set the selection nsCOMPtrselection; result = GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(result)) return result; - if (!selection) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!selection) return NS_ERROR_NULL_POINTER; selection->Collapse(newChildNode, 0); PRInt32 endOffset = aEndOffset-aStartOffset; selection->Extend(newChildNode, endOffset); @@ -5238,10 +5247,10 @@ nsHTMLEditor::SetTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode, IsTextPropertySetByContent(aStartNode, aPropName, aAttribute, aValue, textPropertySet, getter_AddRefs(resultNode)); if (PR_FALSE==textPropertySet) { - result = RemoveTextPropertiesForNodeWithDifferentParents(aStartNode, aStartOffset, - aEndNode, aEndOffset, - aParent, aPropName, aAttribute); - if (NS_FAILED(result)) return result; + result = RemoveTextPropertiesForNodeWithDifferentParents(aStartNode, aStartOffset, + aEndNode, aEndOffset, + aParent, aPropName, aAttribute); + if (NS_FAILED(result)) return result; nsAutoString tag; aPropName->ToString(tag); @@ -5249,16 +5258,16 @@ nsHTMLEditor::SetTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode, nsCOMPtrnewStyleNode; nsCOMPtrdoc; result = GetDocument(getter_AddRefs(doc)); - if (NS_FAILED(result)) return result; - if (!doc) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!doc) return NS_ERROR_NULL_POINTER; nsCOMPtrnewElement; result = doc->CreateElement(tag, getter_AddRefs(newElement)); - if (NS_FAILED(result)) return result; - if (!newElement) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!newElement) return NS_ERROR_NULL_POINTER; newStyleNode = do_QueryInterface(newElement); - if (!newStyleNode) return NS_ERROR_NULL_POINTER; + if (!newStyleNode) return NS_ERROR_NULL_POINTER; result = MoveContiguousContentIntoNewParent(aStartNode, aStartOffset, aEndNode, aEndOffset, aParent, newStyleNode); if (NS_SUCCEEDED(result) && aAttribute && 0!=aAttribute->Length()) { @@ -5271,7 +5280,7 @@ nsHTMLEditor::SetTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode, result = newStyleElement->SetAttribute(*aAttribute, value); } } - if (gNoisy) { printf("---------- end nsTextEditor::SetTextPropertiesForNodesWithSameParent ----------\n"); } + if (gNoisy) { printf("---------- end nsTextEditor::SetTextPropertiesForNodesWithSameParent ----------\n"); } return result; } @@ -5285,7 +5294,7 @@ nsHTMLEditor::MoveContiguousContentIntoNewParent(nsIDOMNode *aStartNode, { if (!aStartNode || !aEndNode || !aNewParentNode) { return NS_ERROR_NULL_POINTER; } if (gNoisy) { printf("--- start nsTextEditor::MoveContiguousContentIntoNewParent ---\n"); } - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) {DebugDumpContent(); } // DEBUG nsresult result = NS_OK; nsCOMPtrstartNode, endNode; @@ -5301,7 +5310,7 @@ nsHTMLEditor::MoveContiguousContentIntoNewParent(nsIDOMNode *aStartNode, { result = nsEditor::SplitNode(aStartNode, aStartOffset, getter_AddRefs(newLeftNode)); if (gNoisy) { printf("split aStartNode, newLeftNode = %p\n", newLeftNode.get()); } - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) {DebugDumpContent(); } // DEBUG } else { if (gNoisy) { printf("did not split aStartNode\n"); } @@ -5324,7 +5333,7 @@ nsHTMLEditor::MoveContiguousContentIntoNewParent(nsIDOMNode *aStartNode, { result = nsEditor::SplitNode(aEndNode, aEndOffset, getter_AddRefs(newRightNode)); if (gNoisy) { printf("split aEndNode, newRightNode = %p\n", newRightNode.get()); } - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) {DebugDumpContent(); } // DEBUG } else { newRightNode = do_QueryInterface(aEndNode); @@ -5353,8 +5362,8 @@ nsHTMLEditor::MoveContiguousContentIntoNewParent(nsIDOMNode *aStartNode, { // insert aNewParentNode into aGrandParentNode result = nsEditor::InsertNode(aNewParentNode, aGrandParentNode, offsetInParent); - if (gNoisy) printf("just after InsertNode 1\n"); - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) printf("just after InsertNode 1\n"); + if (gNoisy) {DebugDumpContent(); } // DEBUG if (NS_SUCCEEDED(result)) { // move the right half of the start node into the new parent node nsCOMPtrintermediateNode; @@ -5362,14 +5371,14 @@ nsHTMLEditor::MoveContiguousContentIntoNewParent(nsIDOMNode *aStartNode, if (NS_SUCCEEDED(result)) { result = nsEditor::DeleteNode(startNode); - if (gNoisy) printf("just after DeleteNode 1\n"); - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) printf("just after DeleteNode 1\n"); + if (gNoisy) {DebugDumpContent(); } // DEBUG if (NS_SUCCEEDED(result)) { PRInt32 childIndex=0; result = nsEditor::InsertNode(startNode, aNewParentNode, childIndex); - if (gNoisy) printf("just after InsertNode 2\n"); - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) printf("just after InsertNode 2\n"); + if (gNoisy) {DebugDumpContent(); } // DEBUG childIndex++; if (NS_SUCCEEDED(result)) { // move all the intermediate nodes into the new parent node @@ -5384,13 +5393,13 @@ nsHTMLEditor::MoveContiguousContentIntoNewParent(nsIDOMNode *aStartNode, // get the next sibling before moving the current child!!! intermediateNode->GetNextSibling(getter_AddRefs(nextSibling)); result = nsEditor::DeleteNode(intermediateNode); - if (gNoisy) printf("just after DeleteNode 3\n"); - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) printf("just after DeleteNode 3\n"); + if (gNoisy) {DebugDumpContent(); } // DEBUG if (NS_SUCCEEDED(result)) - { + { result = nsEditor::InsertNode(intermediateNode, aNewParentNode, childIndex); - if (gNoisy) printf("just after InsertNode 4\n"); - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) printf("just after InsertNode 4\n"); + if (gNoisy) {DebugDumpContent(); } // DEBUG childIndex++; } intermediateNode = do_QueryInterface(nextSibling); @@ -5398,20 +5407,20 @@ nsHTMLEditor::MoveContiguousContentIntoNewParent(nsIDOMNode *aStartNode, if (NS_SUCCEEDED(result)) { // move the left half of the end node into the new parent node result = nsEditor::DeleteNode(newRightNode); - if (gNoisy) printf("just after DeleteNode 5\n"); - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) printf("just after DeleteNode 5\n"); + if (gNoisy) {DebugDumpContent(); } // DEBUG if (NS_SUCCEEDED(result)) { result = nsEditor::InsertNode(newRightNode, aNewParentNode, childIndex); - if (gNoisy) printf("just after InsertNode 5\n"); - if (gNoisy) {DebugDumpContent(); } // DEBUG + if (gNoisy) printf("just after InsertNode 5\n"); + if (gNoisy) {DebugDumpContent(); } // DEBUG // now set the selection if (NS_SUCCEEDED(result)) { nsCOMPtrselection; result = GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(result)) return result; - if (!selection) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!selection) return NS_ERROR_NULL_POINTER; selection->Collapse(startNode, startOffset); selection->Extend(newRightNode, endOffset); } @@ -5484,8 +5493,8 @@ nsHTMLEditor::SetTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRange, nsCOMPtriter; 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; // find our starting point PRBool startIsText = IsTextNode(aStartNode); @@ -5587,8 +5596,8 @@ nsHTMLEditor::SetTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRange, // create a style node for the text in the start parent nsCOMPtrstartNode = do_QueryInterface(startContent); result = startNode->GetParentNode(getter_AddRefs(parent)); - if (NS_FAILED(result)) return result; - if (!parent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!parent) return NS_ERROR_NULL_POINTER; nsCOMPtrnodeAsChar; nodeAsChar = do_QueryInterface(startNode); @@ -5596,18 +5605,18 @@ nsHTMLEditor::SetTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRange, { nodeAsChar->GetLength(&count); if (gNoisy) { printf("processing start node %p.\n", nodeAsChar.get()); } - if (aStartOffset!=(PRInt32)count) - { - result = SetTextPropertiesForNode(startNode, parent, aStartOffset, count, aPropName, aAttribute, aValue); - startOffset = 0; - } + if (aStartOffset!=(PRInt32)count) + { + result = SetTextPropertiesForNode(startNode, parent, aStartOffset, count, aPropName, aAttribute, aValue); + startOffset = 0; + } } else { nsCOMPtrgrandParent; result = parent->GetParentNode(getter_AddRefs(grandParent)); - if (NS_FAILED(result)) return result; - if (!grandParent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!grandParent) return NS_ERROR_NULL_POINTER; if (gNoisy) { printf("processing start node %p.\n", parent.get()); } result = SetTextPropertiesForNode(parent, grandParent, aStartOffset, aStartOffset+1, aPropName, aAttribute, aValue); startNode = do_QueryInterface(parent); @@ -5628,14 +5637,14 @@ nsHTMLEditor::SetTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRange, { nodeAsChar->GetLength(&count); if (gNoisy) { printf("processing end node %p.\n", nodeAsChar.get()); } - if (0!=aEndOffset) - { - result = SetTextPropertiesForNode(endNode, parent, 0, aEndOffset, aPropName, aAttribute, aValue); - // SetTextPropertiesForNode kindly computed the proper selection focus node and offset for us, - // remember them here - selection->GetFocusOffset(&endOffset); - selection->GetFocusNode(getter_AddRefs(endNode)); - } + if (0!=aEndOffset) + { + result = SetTextPropertiesForNode(endNode, parent, 0, aEndOffset, aPropName, aAttribute, aValue); + // SetTextPropertiesForNode kindly computed the proper selection focus node and offset for us, + // remember them here + selection->GetFocusOffset(&endOffset); + selection->GetFocusNode(getter_AddRefs(endNode)); + } } else { @@ -5643,8 +5652,8 @@ nsHTMLEditor::SetTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRange, if (0==aEndOffset) { return NS_ERROR_NOT_IMPLEMENTED; } nsCOMPtrgrandParent; result = parent->GetParentNode(getter_AddRefs(grandParent)); - if (NS_FAILED(result)) return result; - if (!grandParent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!grandParent) return NS_ERROR_NULL_POINTER; if (gNoisy) { printf("processing end node %p.\n", parent.get()); } result = SetTextPropertiesForNode(parent, grandParent, aEndOffset-1, aEndOffset, aPropName, aAttribute, aValue); endNode = do_QueryInterface(parent); @@ -5889,7 +5898,7 @@ nsHTMLEditor::RemoveTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode, nsIAtom *aPropName, const nsString *aAttribute) { - NS_ASSERTION(0, "obsolete"); + NS_ASSERTION(0, "obsolete"); return NS_ERROR_NOT_IMPLEMENTED; } @@ -5974,8 +5983,8 @@ nsHTMLEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStar if (nodeAsChar) { result = endNode->GetParentNode(getter_AddRefs(parent)); - if (NS_FAILED(result)) return result; - if (!parent) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!parent) return NS_ERROR_NULL_POINTER; nodeAsChar->GetLength(&count); if (aEndOffset!=0) { // only do this if at least one child is selected @@ -5997,7 +6006,7 @@ nsHTMLEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStar { skippedEndNode = PR_TRUE; if (gNoisy) { printf("skipping end node because aEndOffset==0\n"); } - } + } } else { @@ -6048,8 +6057,8 @@ nsHTMLEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStar nsCOMPtriter; 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; nsCOMPtrstartContent; startContent = do_QueryInterface(startNode); @@ -6140,8 +6149,8 @@ nsHTMLEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStar } nsCOMPtrselection; result = GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(result)) return result; - if (!selection) return NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) return result; + if (!selection) return NS_ERROR_NULL_POINTER; // set the sel. start point. if we skipped the start node, just use it if (PR_TRUE==skippedStartNode) @@ -6152,7 +6161,7 @@ nsHTMLEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStar // set the sel. end point. if we skipped the end node, just use it if (PR_TRUE==skippedEndNode) endNode = do_QueryInterface(aEndNode); - result = selection->Extend(endNode, rangeEndOffset); + result = selection->Extend(endNode, rangeEndOffset); if (NS_FAILED(result)) return result; if (gNoisy) { printf("RTPFNWDP set selection.\n"); } } @@ -6184,9 +6193,9 @@ nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMSelection *aInSelection) printf("---------- start nsTextEditor::CollapseAdjacentTextNodes ----------\n"); DebugDumpContent(); } - if (!aInSelection) return NS_ERROR_NULL_POINTER; + if (!aInSelection) return NS_ERROR_NULL_POINTER; - nsVoidArray textNodes; // we can't actually do anything during iteration, so store the text nodes in an array + nsVoidArray textNodes; // we can't actually do anything during iteration, so store the text nodes in an array // don't bother ref counting them because we know we can hold them for the // lifetime of this method @@ -6210,7 +6219,7 @@ nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMSelection *aInSelection) anchorText = do_QueryInterface(anchor); if (anchorText) { - textNodes.AppendElement((void*)(anchorText.get())); + textNodes.AppendElement((void*)(anchorText.get())); } aInSelection->GetFocusNode(getter_AddRefs(focus)); focusText = do_QueryInterface(focus); @@ -6245,7 +6254,7 @@ nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMSelection *aInSelection) nsCOMPtr text = do_QueryInterface(content); if (text && anchorText.get() != text.get() && focusText.get() != text.get()) { - textNodes.AppendElement((void*)(text.get())); + textNodes.AppendElement((void*)(text.get())); } iter->Next(); iter->CurrentNode(getter_AddRefs(content)); @@ -6256,18 +6265,18 @@ nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMSelection *aInSelection) // now add the focus to the list, if it's a text node if (focusText) { - textNodes.AppendElement((void*)(focusText.get())); + textNodes.AppendElement((void*)(focusText.get())); } // now that I have a list of text nodes, collapse adjacent text nodes - PRInt32 count = textNodes.Count(); + PRInt32 count = textNodes.Count(); const PRInt32 initialCount = count; - while (1 prevSiblingOfRightTextNode; + // get the prev sibling of the right node, and see if it's leftTextNode + nsCOMPtr prevSiblingOfRightTextNode; result = rightTextNode->GetPreviousSibling(getter_AddRefs(prevSiblingOfRightTextNode)); if (NS_FAILED(result)) return result; if (prevSiblingOfRightTextNode) @@ -6335,7 +6344,7 @@ nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMSelection *aInSelection) // remove the rightmost remaining text node from the array and work our way towards the beginning textNodes.RemoveElementAt(0); // remove the leftmost text node from the list count --; - } + } ResetTextSelectionForRange(parentForSelection, rangeStartOffset, rangeEndOffset, aInSelection); @@ -6345,6 +6354,6 @@ nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMSelection *aInSelection) DebugDumpContent(); } - return result; + return result; } diff --git a/editor/libeditor/html/nsHTMLEditor.h b/editor/libeditor/html/nsHTMLEditor.h index c606d3332e3..07f5c1fc00c 100644 --- a/editor/libeditor/html/nsHTMLEditor.h +++ b/editor/libeditor/html/nsHTMLEditor.h @@ -243,7 +243,7 @@ protected: // key event helpers NS_IMETHOD TabInTable(PRBool inIsShift, PRBool *outHandled); - NS_IMETHOD InsertBR(); + NS_IMETHOD InsertBR(nsCOMPtr *outBRNode); // Table Editing (implemented in EditTable.cpp) @@ -474,6 +474,9 @@ protected: PRBool mIsComposing; PRInt32 mMaxTextLength; +public: + static nsIAtom *gTypingTxnName; + // friends friend class nsHTMLEditRules; friend class nsTextEditRules; diff --git a/editor/libeditor/text/nsTextEditRules.cpp b/editor/libeditor/text/nsTextEditRules.cpp index ab31f53b0cf..eb3cd851935 100644 --- a/editor/libeditor/text/nsTextEditRules.cpp +++ b/editor/libeditor/text/nsTextEditRules.cpp @@ -19,8 +19,6 @@ #include "nsTextEditRules.h" #include "nsEditor.h" -#include "PlaceholderTxn.h" -#include "InsertTextTxn.h" #include "nsCOMPtr.h" #include "nsIDOMNode.h" @@ -140,7 +138,6 @@ nsTextEditRules::WillDoAction(nsIDOMSelection *aSelection, case kInsertText: return WillInsertText(aSelection, aCancel, - info->placeTxn, info->inString, info->outString, info->typeInState, @@ -265,7 +262,6 @@ nsTextEditRules::DidInsertBreak(nsIDOMSelection *aSelection, nsresult aResult) nsresult nsTextEditRules::WillInsertText(nsIDOMSelection *aSelection, PRBool *aCancel, - PlaceholderTxn **aTxn, const nsString *aInString, nsString *aOutString, TypeInState aTypeInState, @@ -293,7 +289,7 @@ nsTextEditRules::WillInsertText(nsIDOMSelection *aSelection, // do text insertion PRBool bCancel; - res = DoTextInsertion(aSelection, &bCancel, aTxn, aOutString, aTypeInState); + res = DoTextInsertion(aSelection, &bCancel, aOutString, aTypeInState); return res; } @@ -1059,7 +1055,6 @@ nsTextEditRules::EchoInsertionToPWBuff(nsIDOMSelection *aSelection, nsString *aO nsresult nsTextEditRules::DoTextInsertion(nsIDOMSelection *aSelection, PRBool *aCancel, - PlaceholderTxn **aTxn, const nsString *aInString, TypeInState aTypeInState) { @@ -1070,14 +1065,6 @@ nsTextEditRules::DoTextInsertion(nsIDOMSelection *aSelection, // 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)) diff --git a/editor/libeditor/text/nsTextEditRules.h b/editor/libeditor/text/nsTextEditRules.h index 0fa8df0cac9..66f08dfde90 100644 --- a/editor/libeditor/text/nsTextEditRules.h +++ b/editor/libeditor/text/nsTextEditRules.h @@ -27,7 +27,6 @@ #include "nsEditRules.h" #include "TypeInState.h" -class PlaceholderTxn; class nsTextEditor; /** Object that encapsulates HTML text-specific editing rules. @@ -86,7 +85,6 @@ protected: // nsTextEditRules implementation methods nsresult WillInsertText(nsIDOMSelection *aSelection, PRBool *aCancel, - PlaceholderTxn **aTxn, const nsString *inString, nsString *outString, TypeInState typeInState, @@ -180,7 +178,6 @@ protected: /** do the actual text insertion */ nsresult DoTextInsertion(nsIDOMSelection *aSelection, PRBool *aCancel, - PlaceholderTxn **aTxn, const nsString *aInString, TypeInState aTypeInState); @@ -199,7 +196,6 @@ class nsTextRulesInfo : public nsRulesInfo nsTextRulesInfo(int aAction) : nsRulesInfo(aAction), - placeTxn(0), inString(0), outString(0), outputFormat(0), @@ -215,7 +211,6 @@ class nsTextRulesInfo : public nsRulesInfo virtual ~nsTextRulesInfo() {}; // kInsertText - PlaceholderTxn **placeTxn; const nsString *inString; nsString *outString; const nsString *outputFormat; diff --git a/editor/public/nsIEditor.h b/editor/public/nsIEditor.h index 9693fcf1498..046542cdb0e 100644 --- a/editor/public/nsIEditor.h +++ b/editor/public/nsIEditor.h @@ -203,6 +203,8 @@ public: */ NS_IMETHOD EndTransaction()=0; + NS_IMETHOD BeginPlaceHolderTransaction(nsIAtom *aName)=0; + NS_IMETHOD EndPlaceHolderTransaction()=0; /* ------------ Clipboard methods -------------- */