зеркало из https://github.com/mozilla/pjs.git
revised UNDO; introduced first cut at the "mozdiv" typing rules
This commit is contained in:
Родитель
1c960f2fad
Коммит
75ecd98021
|
@ -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<nsISupportsWeakReference>::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<count)
|
||||
NS_NOTREACHED("tried to merge into a placeholder that was in forwarding mode!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
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
|
||||
{ // merge typing transactions if the selection matches
|
||||
if (mName.get() == nsHTMLEditor::gTypingTxnName)
|
||||
{
|
||||
nsCOMPtr<nsIAbsorbingTransaction> 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<nsIDOMNode> 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<nsIDOMNode> *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<nsIAbsorbingTransaction> plcTxn = do_QueryReferent(mForwarding);
|
||||
if (plcTxn) plcTxn->EndPlaceHolderBatch();
|
||||
}
|
||||
|
||||
// if we are a typing transaction, remember our selection state
|
||||
if (mName.get() == nsHTMLEditor::gTypingTxnName)
|
||||
{
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
if (!ps) return NS_ERROR_NOT_INITIALIZED;
|
||||
nsCOMPtr<nsIDOMSelection> 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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<nsIDOMNode> *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<nsIDOMNode> mStartNode, mEndNode; // selection nodes at beginning and end of operation
|
||||
PRInt32 mStartOffset, mEndOffset; // selection offsets at beginning and end of operation
|
||||
nsWeakPtr mForwarding;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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<nsIAbsorbingTransaction> 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<nsITransaction> theTxn = do_QueryInterface(plcTxn);
|
||||
nsITransaction* txn = theTxn;
|
||||
// we want to escape from this routine with a positive refcount
|
||||
txn->AddRef();
|
||||
Do(txn);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMSelection>selection;
|
||||
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<nsIDOMSelection> 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<nsIAbsorbingTransaction> 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<nsIDOMNode> parent;
|
||||
nsEditor::GetNodeLocation(aParentNode, &parent, &aOffset);
|
||||
aParentNode = parent;
|
||||
aOffset++; // _after_ the text node
|
||||
}
|
||||
// look at the child at 'aOffset'
|
||||
nsCOMPtr<nsIDOMNode> 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<nsITextContent> 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<nsIDOMSelection> selection;
|
||||
result = GetSelection(getter_AddRefs(selection));
|
||||
if ((NS_SUCCEEDED(result)) && selection)
|
||||
|
@ -3138,8 +3274,6 @@ nsEditor::SetInputMethodText(const nsString& aStringToInsert, nsIPrivateTextRang
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
EndTransaction();
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -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<nsITransactionManager> mTxnMgr;
|
||||
nsCOMPtr<nsIEditProperty> mEditProperty;
|
||||
nsCOMPtr<nsICSSStyleSheet> mLastStyleSheet; // is owning this dangerous?
|
||||
nsWeakPtr mPlaceHolderTxn;
|
||||
nsIAtom *mPlaceHolderName;
|
||||
PRInt32 mPlaceHolderBatch;
|
||||
nsCOMPtr<nsIDOMNode> mTxnStartNode;
|
||||
PRInt32 mTxnStartOffset;
|
||||
|
||||
//
|
||||
// data necessary to build IME transactions
|
||||
|
|
|
@ -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<nsIEditor> mEd;
|
||||
public:
|
||||
nsAutoPlaceHolderBatch( nsIEditor *aEd, nsIAtom *atom) : mEd(do_QueryInterface(aEd))
|
||||
{ if (mEd) mEd->BeginPlaceHolderTransaction(atom); }
|
||||
~nsAutoPlaceHolderBatch() { if (mEd) mEd->EndPlaceHolderTransaction(); }
|
||||
};
|
||||
|
||||
|
||||
class nsAutoSelectionReset
|
||||
{
|
||||
|
|
|
@ -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<nsIDOMNode> 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<nsIDOMNode> citeNode, selNode;
|
||||
PRInt32 selOffset, newOffset;
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIDOMNode> 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<nsIDOMNode> 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<nsIDOMCharacterData> 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<nsIDOMNode> 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<nsIDOMNode> 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<nsIDOMNode> 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<nsIDOMNode> 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<nsIDOMNode> brNode;
|
||||
res = mEditor->InsertBR(&brNode); // only inserts a br node
|
||||
if (NS_FAILED(res)) return res;
|
||||
// give it special moz attr
|
||||
nsCOMPtr<nsIDOMElement> 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<nsIDOMNode> 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<nsIDOMNode> parent;
|
||||
blockParent->GetParentNode(getter_AddRefs(parent));
|
||||
nsCOMPtr <nsIDOMNode> 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 <br>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<nsIAtom> leftAtom = mEditor->GetTag(leftParent);
|
||||
nsCOMPtr<nsIAtom> rightAtom = mEditor->GetTag(rightParent);
|
||||
|
||||
if (leftAtom.get() == rightAtom.get())
|
||||
if (mEditor->NodesSameType(leftParent, rightParent))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> topParent;
|
||||
leftParent->GetParentNode(getter_AddRefs(topParent));
|
||||
|
@ -454,10 +577,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection, nsIEditor::ESe
|
|||
// are the blocks of same type?
|
||||
nsCOMPtr<nsIDOMNode> leftParent = mEditor->GetBlockNodeParent(node);
|
||||
nsCOMPtr<nsIDOMNode> rightParent = mEditor->GetBlockNodeParent(nextNode);
|
||||
nsCOMPtr<nsIAtom> leftAtom = mEditor->GetTag(leftParent);
|
||||
nsCOMPtr<nsIAtom> rightAtom = mEditor->GetTag(rightParent);
|
||||
|
||||
if (leftAtom.get() == rightAtom.get())
|
||||
if (mEditor->NodesSameType(leftParent, rightParent))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIAtom> leftAtom = mEditor->GetTag(leftParent);
|
||||
nsCOMPtr<nsIAtom> rightAtom = mEditor->GetTag(rightParent);
|
||||
|
||||
if (leftAtom.get() == rightAtom.get())
|
||||
if (mEditor->NodesSameType(leftParent, rightParent))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIDOMElement> 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 <hr>, or <br>, 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<nsIContentIterator> 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<nsIDOMNode> *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<nsIDOMElement> 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 <body>
|
||||
|
@ -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<nsIDOMCharacterData> nodeAsText = do_QueryInterface(aNode);
|
||||
if (nodeAsText && aOffset) return PR_FALSE; // there are chars in front of us
|
||||
|
||||
nsCOMPtr<nsIDOMNode> priorNode;
|
||||
nsresult res = GetPriorHTMLNode(aNode, aOffset, &priorNode);
|
||||
if (NS_FAILED(res)) return PR_TRUE;
|
||||
if (!priorNode) return PR_TRUE;
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIDOMCharacterData> nodeAsText = do_QueryInterface(aNode);
|
||||
if (nodeAsText)
|
||||
{
|
||||
PRUint32 strLength;
|
||||
nodeAsText->GetLength(&strLength);
|
||||
if (strLength > aOffset) return PR_FALSE; // there are chars in after us
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> nextNode;
|
||||
nsresult res = GetNextHTMLNode(aNode, aOffset, &nextNode);
|
||||
if (NS_FAILED(res)) return PR_TRUE;
|
||||
if (!nextNode) return PR_TRUE;
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIDOMNode> *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<nsIDOMNode> parentNode;
|
||||
|
@ -2271,7 +2539,6 @@ nsHTMLEditRules::InsertTab(nsIDOMSelection *aSelection,
|
|||
nsresult
|
||||
nsHTMLEditRules::InsertSpace(nsIDOMSelection *aSelection,
|
||||
PRBool *aCancel,
|
||||
PlaceholderTxn **aTxn,
|
||||
nsString *outString)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> 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 <p> 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<nsIDOMNode> 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<nsIDOMElement> 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<nsIDOMNode> parent;
|
||||
nsCOMPtr<nsIDOMNode> parent, firstChild;
|
||||
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
parent->GetFirstChild(getter_AddRefs(child));
|
||||
if (!child) return NS_ERROR_FAILURE;
|
||||
|
||||
if (!mEditor->IsEditable(child))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> tmp;
|
||||
res = 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<nsIDOMNode> parent;
|
||||
nsCOMPtr<nsIDOMNode> parent, lastChild;
|
||||
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
parent->GetLastChild(getter_AddRefs(child));
|
||||
if (!child) return NS_ERROR_FAILURE;
|
||||
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<nsIDOMNode> *aOutFirstChild)
|
||||
{
|
||||
// check parms
|
||||
if (!aOutFirstChild || !aNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// init out parms
|
||||
*aOutFirstChild = nsnull;
|
||||
|
||||
// find first editable child
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
nsresult res = aNode->GetFirstChild(getter_AddRefs(child));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
while (child && !mEditor->IsEditable(child))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIDOMNode> *aOutLastChild)
|
||||
{
|
||||
// check parms
|
||||
if (!aOutLastChild || !aNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// init out parms
|
||||
*aOutLastChild = nsnull;
|
||||
|
||||
// find last editable child
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
nsresult res = aNode->GetLastChild(getter_AddRefs(child));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
while (child && !mEditor->IsEditable(child))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIDOMNode> parent;
|
||||
aNodeLeft->GetParentNode(getter_AddRefs(parent));
|
||||
PRInt32 parOffset;
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIDOMNode> 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<nsIDOMNode> mozDiv;
|
||||
res = ReplaceContainer(curNode, &mozDiv, "div");
|
||||
if (NS_FAILED(res)) return res;
|
||||
// give it special moz attr
|
||||
nsCOMPtr<nsIDOMElement> 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;
|
||||
}
|
||||
|
|
|
@ -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<nsIDOMNode> *outDiv);
|
||||
nsresult GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
|
@ -115,10 +121,12 @@ protected:
|
|||
|
||||
nsresult ReplaceContainer(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, const nsString &aNodeType);
|
||||
nsresult RemoveContainer(nsIDOMNode *inNode);
|
||||
nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, nsString &aNodeType);
|
||||
nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, const nsString &aNodeType);
|
||||
|
||||
nsresult IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst);
|
||||
nsresult IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast);
|
||||
nsresult GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild);
|
||||
nsresult GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild);
|
||||
|
||||
nsresult JoinNodesSmart( nsIDOMNode *aNodeLeft,
|
||||
nsIDOMNode *aNodeRight,
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -243,7 +243,7 @@ protected:
|
|||
|
||||
// key event helpers
|
||||
NS_IMETHOD TabInTable(PRBool inIsShift, PRBool *outHandled);
|
||||
NS_IMETHOD InsertBR();
|
||||
NS_IMETHOD InsertBR(nsCOMPtr<nsIDOMNode> *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;
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<nsISupportsWeakReference>::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<count)
|
||||
NS_NOTREACHED("tried to merge into a placeholder that was in forwarding mode!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
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
|
||||
{ // merge typing transactions if the selection matches
|
||||
if (mName.get() == nsHTMLEditor::gTypingTxnName)
|
||||
{
|
||||
nsCOMPtr<nsIAbsorbingTransaction> 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<nsIDOMNode> 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<nsIDOMNode> *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<nsIAbsorbingTransaction> plcTxn = do_QueryReferent(mForwarding);
|
||||
if (plcTxn) plcTxn->EndPlaceHolderBatch();
|
||||
}
|
||||
|
||||
// if we are a typing transaction, remember our selection state
|
||||
if (mName.get() == nsHTMLEditor::gTypingTxnName)
|
||||
{
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
if (!ps) return NS_ERROR_NOT_INITIALIZED;
|
||||
nsCOMPtr<nsIDOMSelection> 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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<nsIDOMNode> *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<nsIDOMNode> mStartNode, mEndNode; // selection nodes at beginning and end of operation
|
||||
PRInt32 mStartOffset, mEndOffset; // selection offsets at beginning and end of operation
|
||||
nsWeakPtr mForwarding;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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<nsIAbsorbingTransaction> 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<nsITransaction> theTxn = do_QueryInterface(plcTxn);
|
||||
nsITransaction* txn = theTxn;
|
||||
// we want to escape from this routine with a positive refcount
|
||||
txn->AddRef();
|
||||
Do(txn);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMSelection>selection;
|
||||
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<nsIDOMSelection> 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<nsIAbsorbingTransaction> 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<nsIDOMNode> parent;
|
||||
nsEditor::GetNodeLocation(aParentNode, &parent, &aOffset);
|
||||
aParentNode = parent;
|
||||
aOffset++; // _after_ the text node
|
||||
}
|
||||
// look at the child at 'aOffset'
|
||||
nsCOMPtr<nsIDOMNode> 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<nsITextContent> 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<nsIDOMSelection> selection;
|
||||
result = GetSelection(getter_AddRefs(selection));
|
||||
if ((NS_SUCCEEDED(result)) && selection)
|
||||
|
@ -3138,8 +3274,6 @@ nsEditor::SetInputMethodText(const nsString& aStringToInsert, nsIPrivateTextRang
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
EndTransaction();
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -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<nsITransactionManager> mTxnMgr;
|
||||
nsCOMPtr<nsIEditProperty> mEditProperty;
|
||||
nsCOMPtr<nsICSSStyleSheet> mLastStyleSheet; // is owning this dangerous?
|
||||
nsWeakPtr mPlaceHolderTxn;
|
||||
nsIAtom *mPlaceHolderName;
|
||||
PRInt32 mPlaceHolderBatch;
|
||||
nsCOMPtr<nsIDOMNode> mTxnStartNode;
|
||||
PRInt32 mTxnStartOffset;
|
||||
|
||||
//
|
||||
// data necessary to build IME transactions
|
||||
|
|
|
@ -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<nsIEditor> mEd;
|
||||
public:
|
||||
nsAutoPlaceHolderBatch( nsIEditor *aEd, nsIAtom *atom) : mEd(do_QueryInterface(aEd))
|
||||
{ if (mEd) mEd->BeginPlaceHolderTransaction(atom); }
|
||||
~nsAutoPlaceHolderBatch() { if (mEd) mEd->EndPlaceHolderTransaction(); }
|
||||
};
|
||||
|
||||
|
||||
class nsAutoSelectionReset
|
||||
{
|
||||
|
|
|
@ -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<nsIDOMNode> 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<nsIDOMNode> citeNode, selNode;
|
||||
PRInt32 selOffset, newOffset;
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIDOMNode> 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<nsIDOMNode> 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<nsIDOMCharacterData> 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<nsIDOMNode> 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<nsIDOMNode> 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<nsIDOMNode> 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<nsIDOMNode> 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<nsIDOMNode> brNode;
|
||||
res = mEditor->InsertBR(&brNode); // only inserts a br node
|
||||
if (NS_FAILED(res)) return res;
|
||||
// give it special moz attr
|
||||
nsCOMPtr<nsIDOMElement> 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<nsIDOMNode> 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<nsIDOMNode> parent;
|
||||
blockParent->GetParentNode(getter_AddRefs(parent));
|
||||
nsCOMPtr <nsIDOMNode> 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 <br>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<nsIAtom> leftAtom = mEditor->GetTag(leftParent);
|
||||
nsCOMPtr<nsIAtom> rightAtom = mEditor->GetTag(rightParent);
|
||||
|
||||
if (leftAtom.get() == rightAtom.get())
|
||||
if (mEditor->NodesSameType(leftParent, rightParent))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> topParent;
|
||||
leftParent->GetParentNode(getter_AddRefs(topParent));
|
||||
|
@ -454,10 +577,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection, nsIEditor::ESe
|
|||
// are the blocks of same type?
|
||||
nsCOMPtr<nsIDOMNode> leftParent = mEditor->GetBlockNodeParent(node);
|
||||
nsCOMPtr<nsIDOMNode> rightParent = mEditor->GetBlockNodeParent(nextNode);
|
||||
nsCOMPtr<nsIAtom> leftAtom = mEditor->GetTag(leftParent);
|
||||
nsCOMPtr<nsIAtom> rightAtom = mEditor->GetTag(rightParent);
|
||||
|
||||
if (leftAtom.get() == rightAtom.get())
|
||||
if (mEditor->NodesSameType(leftParent, rightParent))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIAtom> leftAtom = mEditor->GetTag(leftParent);
|
||||
nsCOMPtr<nsIAtom> rightAtom = mEditor->GetTag(rightParent);
|
||||
|
||||
if (leftAtom.get() == rightAtom.get())
|
||||
if (mEditor->NodesSameType(leftParent, rightParent))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIDOMElement> 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 <hr>, or <br>, 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<nsIContentIterator> 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<nsIDOMNode> *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<nsIDOMElement> 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 <body>
|
||||
|
@ -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<nsIDOMCharacterData> nodeAsText = do_QueryInterface(aNode);
|
||||
if (nodeAsText && aOffset) return PR_FALSE; // there are chars in front of us
|
||||
|
||||
nsCOMPtr<nsIDOMNode> priorNode;
|
||||
nsresult res = GetPriorHTMLNode(aNode, aOffset, &priorNode);
|
||||
if (NS_FAILED(res)) return PR_TRUE;
|
||||
if (!priorNode) return PR_TRUE;
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIDOMCharacterData> nodeAsText = do_QueryInterface(aNode);
|
||||
if (nodeAsText)
|
||||
{
|
||||
PRUint32 strLength;
|
||||
nodeAsText->GetLength(&strLength);
|
||||
if (strLength > aOffset) return PR_FALSE; // there are chars in after us
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> nextNode;
|
||||
nsresult res = GetNextHTMLNode(aNode, aOffset, &nextNode);
|
||||
if (NS_FAILED(res)) return PR_TRUE;
|
||||
if (!nextNode) return PR_TRUE;
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIDOMNode> *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<nsIDOMNode> parentNode;
|
||||
|
@ -2271,7 +2539,6 @@ nsHTMLEditRules::InsertTab(nsIDOMSelection *aSelection,
|
|||
nsresult
|
||||
nsHTMLEditRules::InsertSpace(nsIDOMSelection *aSelection,
|
||||
PRBool *aCancel,
|
||||
PlaceholderTxn **aTxn,
|
||||
nsString *outString)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> 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 <p> 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<nsIDOMNode> 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<nsIDOMElement> 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<nsIDOMNode> parent;
|
||||
nsCOMPtr<nsIDOMNode> parent, firstChild;
|
||||
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
parent->GetFirstChild(getter_AddRefs(child));
|
||||
if (!child) return NS_ERROR_FAILURE;
|
||||
|
||||
if (!mEditor->IsEditable(child))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> tmp;
|
||||
res = 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<nsIDOMNode> parent;
|
||||
nsCOMPtr<nsIDOMNode> parent, lastChild;
|
||||
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
parent->GetLastChild(getter_AddRefs(child));
|
||||
if (!child) return NS_ERROR_FAILURE;
|
||||
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<nsIDOMNode> *aOutFirstChild)
|
||||
{
|
||||
// check parms
|
||||
if (!aOutFirstChild || !aNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// init out parms
|
||||
*aOutFirstChild = nsnull;
|
||||
|
||||
// find first editable child
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
nsresult res = aNode->GetFirstChild(getter_AddRefs(child));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
while (child && !mEditor->IsEditable(child))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIDOMNode> *aOutLastChild)
|
||||
{
|
||||
// check parms
|
||||
if (!aOutLastChild || !aNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// init out parms
|
||||
*aOutLastChild = nsnull;
|
||||
|
||||
// find last editable child
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
nsresult res = aNode->GetLastChild(getter_AddRefs(child));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
while (child && !mEditor->IsEditable(child))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIDOMNode> parent;
|
||||
aNodeLeft->GetParentNode(getter_AddRefs(parent));
|
||||
PRInt32 parOffset;
|
||||
nsCOMPtr<nsIDOMNode> 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<nsIDOMNode> 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<nsIDOMNode> mozDiv;
|
||||
res = ReplaceContainer(curNode, &mozDiv, "div");
|
||||
if (NS_FAILED(res)) return res;
|
||||
// give it special moz attr
|
||||
nsCOMPtr<nsIDOMElement> 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;
|
||||
}
|
||||
|
|
|
@ -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<nsIDOMNode> *outDiv);
|
||||
nsresult GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
|
@ -115,10 +121,12 @@ protected:
|
|||
|
||||
nsresult ReplaceContainer(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, const nsString &aNodeType);
|
||||
nsresult RemoveContainer(nsIDOMNode *inNode);
|
||||
nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, nsString &aNodeType);
|
||||
nsresult InsertContainerAbove(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, const nsString &aNodeType);
|
||||
|
||||
nsresult IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst);
|
||||
nsresult IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast);
|
||||
nsresult GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild);
|
||||
nsresult GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild);
|
||||
|
||||
nsresult JoinNodesSmart( nsIDOMNode *aNodeLeft,
|
||||
nsIDOMNode *aNodeRight,
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -243,7 +243,7 @@ protected:
|
|||
|
||||
// key event helpers
|
||||
NS_IMETHOD TabInTable(PRBool inIsShift, PRBool *outHandled);
|
||||
NS_IMETHOD InsertBR();
|
||||
NS_IMETHOD InsertBR(nsCOMPtr<nsIDOMNode> *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;
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -203,6 +203,8 @@ public:
|
|||
*/
|
||||
NS_IMETHOD EndTransaction()=0;
|
||||
|
||||
NS_IMETHOD BeginPlaceHolderTransaction(nsIAtom *aName)=0;
|
||||
NS_IMETHOD EndPlaceHolderTransaction()=0;
|
||||
|
||||
/* ------------ Clipboard methods -------------- */
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче