зеркало из https://github.com/mozilla/pjs.git
added PlaceholderTxn. This is an aggregate transaction that sits on the undo stack
and merges in subsequent transactions indiscriminately until it's told to stop. It also gives the last transaction in its child list a chance to merge the next transaction. All this is in support of complex transactions that result in text insertion being able to collapse into a single undoable event. Also improved tracking of bogus content node used when document is empty.
This commit is contained in:
Родитель
d7a2ff8486
Коммит
2b8c73f66e
|
@ -167,7 +167,8 @@ NS_IMETHODIMP DeleteRangeTxn::Undo(void)
|
|||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
result = mEditor->GetSelection(getter_AddRefs(selection));
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
result = selection->Collapse(mStartParent, mStartOffset);
|
||||
selection->Collapse(mStartParent, mStartOffset);
|
||||
selection->Extend(mEndParent, mEndOffset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -153,26 +153,6 @@ NS_IMETHODIMP EditAggregateTxn::AppendChild(EditTxn *aTxn)
|
|||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP EditAggregateTxn::SetName(nsIAtom *aName)
|
||||
{
|
||||
mName = do_QueryInterface(aName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP EditAggregateTxn::GetName(nsIAtom **aName)
|
||||
{
|
||||
if (aName)
|
||||
{
|
||||
if (mName)
|
||||
{
|
||||
*aName = mName;
|
||||
NS_ADDREF(*aName);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP EditAggregateTxn::GetCount(PRInt32 *aCount)
|
||||
{
|
||||
if (!aCount) {
|
||||
|
@ -205,6 +185,28 @@ NS_IMETHODIMP EditAggregateTxn::GetTxnAt(PRInt32 aIndex, EditTxn **aTxn)
|
|||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP EditAggregateTxn::SetName(nsIAtom *aName)
|
||||
{
|
||||
mName = do_QueryInterface(aName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP EditAggregateTxn::GetName(nsIAtom **aName)
|
||||
{
|
||||
if (aName)
|
||||
{
|
||||
if (mName)
|
||||
{
|
||||
*aName = mName;
|
||||
NS_ADDREF(*aName);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -71,10 +71,10 @@ public:
|
|||
*/
|
||||
NS_IMETHOD GetTxnAt(PRInt32 aIndex, EditTxn **aTxn);
|
||||
|
||||
/** set the name assigned to this aggregate txn */
|
||||
/** set the name assigned to this txn */
|
||||
NS_IMETHOD SetName(nsIAtom *aName);
|
||||
|
||||
/** get the name assigned to this aggregate txn */
|
||||
/** get the name assigned to this txn */
|
||||
NS_IMETHOD GetName(nsIAtom **aName);
|
||||
|
||||
protected:
|
||||
|
@ -82,7 +82,6 @@ protected:
|
|||
//XXX: if this was an nsISupportsArray, it would handle refcounting for us
|
||||
nsVoidArray * mChildren;
|
||||
nsCOMPtr<nsIAtom> mName;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,8 +20,7 @@
|
|||
#define EditTxn_h__
|
||||
|
||||
#include "nsITransaction.h"
|
||||
|
||||
class nsIDOMNode;
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#define EDIT_TXN_IID \
|
||||
{/* c5ea31b0-ac48-11d2-86d8-000064657374 */ \
|
||||
|
@ -31,6 +30,8 @@ class nsIDOMNode;
|
|||
/**
|
||||
* base class for all document editing transactions.
|
||||
* provides default concrete behavior for all nsITransaction methods.
|
||||
* EditTxns optionally have a name. This name is for internal purposes only,
|
||||
* it is never seen by the user or by any external entity.
|
||||
*/
|
||||
class EditTxn : public nsITransaction
|
||||
{
|
||||
|
|
|
@ -119,19 +119,23 @@ NS_IMETHODIMP InsertTextTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransacti
|
|||
otherTxn->GetName(getter_AddRefs(txnName));
|
||||
if (txnName.get()==gInsertTextTxnName)
|
||||
{ // yep, it's one of ours. By definition, it must contain only
|
||||
// a single InsertTextTxn
|
||||
// another aggregate with a single child,
|
||||
// or a single InsertTextTxn
|
||||
nsCOMPtr<EditTxn> childTxn;
|
||||
otherTxn->GetTxnAt(0, getter_AddRefs(childTxn));
|
||||
nsCOMPtr<InsertTextTxn> otherInsertTxn;
|
||||
otherInsertTxn = do_QueryInterface(childTxn, &result);
|
||||
if (otherInsertTxn)
|
||||
if (childTxn)
|
||||
{
|
||||
if (PR_TRUE==IsSequentialInsert(otherInsertTxn))
|
||||
nsCOMPtr<InsertTextTxn> otherInsertTxn;
|
||||
otherInsertTxn = do_QueryInterface(childTxn, &result);
|
||||
if (otherInsertTxn)
|
||||
{
|
||||
nsAutoString otherData;
|
||||
otherInsertTxn->GetData(otherData);
|
||||
mStringToInsert += otherData;
|
||||
*aDidMerge = PR_TRUE;
|
||||
if (PR_TRUE==IsSequentialInsert(otherInsertTxn))
|
||||
{
|
||||
nsAutoString otherData;
|
||||
otherInsertTxn->GetData(otherData);
|
||||
mStringToInsert += otherData;
|
||||
*aDidMerge = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ CPPSRCS = \
|
|||
DeleteTableRowTxn.cpp \
|
||||
JoinTableCellsTxn.cpp \
|
||||
InsertTextTxn.cpp \
|
||||
PlaceholderTxn.cpp \
|
||||
DeleteTextTxn.cpp \
|
||||
CreateElementTxn.cpp \
|
||||
InsertElementTxn.cpp \
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "PlaceholderTxn.h"
|
||||
#include "nsVoidArray.h"
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
static PRBool gNoisy = PR_TRUE;
|
||||
#else
|
||||
static const PRBool gNoisy = PR_FALSE;
|
||||
#endif
|
||||
|
||||
|
||||
PlaceholderTxn::PlaceholderTxn()
|
||||
: EditAggregateTxn()
|
||||
{
|
||||
mAbsorb=PR_TRUE;
|
||||
}
|
||||
|
||||
|
||||
PlaceholderTxn::~PlaceholderTxn()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP PlaceholderTxn::Do(void)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP PlaceholderTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransaction)
|
||||
{
|
||||
// set out param default value
|
||||
if (nsnull!=aDidMerge)
|
||||
*aDidMerge=PR_FALSE;
|
||||
nsresult result = NS_OK;
|
||||
if ((nsnull!=aDidMerge) && (nsnull!=aTransaction))
|
||||
{
|
||||
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;
|
||||
}
|
||||
else
|
||||
{ // let our last child txn make the choice
|
||||
PRInt32 count = mChildren->Count();
|
||||
if (0<count)
|
||||
{
|
||||
EditTxn *lastTxn = (EditTxn*)(mChildren->ElementAt(count-1));
|
||||
if (lastTxn)
|
||||
{
|
||||
lastTxn->Merge(aDidMerge, aTransaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef AggregatePlaceholderTxn_h__
|
||||
#define AggregatePlaceholderTxn_h__
|
||||
|
||||
#include "EditAggregateTxn.h"
|
||||
|
||||
#define PLACEHOLDER_TXN_IID \
|
||||
{/* {0CE9FB00-D9D1-11d2-86DE-000064657374} */ \
|
||||
0x0CE9FB00, 0xD9D1, 0x11d2, \
|
||||
{0x86, 0xde, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
public:
|
||||
|
||||
private:
|
||||
PlaceholderTxn();
|
||||
|
||||
public:
|
||||
|
||||
virtual ~PlaceholderTxn();
|
||||
|
||||
NS_IMETHOD Do(void);
|
||||
|
||||
NS_IMETHOD Merge(PRBool *aDidMerge, nsITransaction *aTransaction);
|
||||
|
||||
NS_IMETHOD SetAbsorb(PRBool aAbsorb);
|
||||
|
||||
friend class TransactionFactory;
|
||||
|
||||
protected:
|
||||
|
||||
PRBool mAbsorb;
|
||||
|
||||
};
|
||||
|
||||
inline NS_IMETHODIMP PlaceholderTxn::SetAbsorb(PRBool aAbsorb)
|
||||
{
|
||||
mAbsorb = aAbsorb;
|
||||
return NS_OK;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -19,6 +19,7 @@
|
|||
#include "TransactionFactory.h"
|
||||
// transactions this factory knows how to build
|
||||
#include "EditAggregateTxn.h"
|
||||
#include "PlaceholderTxn.h"
|
||||
#include "InsertTextTxn.h"
|
||||
#include "DeleteTextTxn.h"
|
||||
#include "CreateElementTxn.h"
|
||||
|
@ -39,6 +40,7 @@
|
|||
#include "JoinTableCellsTxn.h"
|
||||
|
||||
static NS_DEFINE_IID(kEditAggregateTxnIID, EDIT_AGGREGATE_TXN_IID);
|
||||
static NS_DEFINE_IID(kPlaceholderTxnIID, PLACEHOLDER_TXN_IID);
|
||||
static NS_DEFINE_IID(kInsertTextTxnIID, INSERT_TEXT_TXN_IID);
|
||||
static NS_DEFINE_IID(kDeleteTextTxnIID, DELETE_TEXT_TXN_IID);
|
||||
static NS_DEFINE_IID(kCreateElementTxnIID, CREATE_ELEMENT_TXN_IID);
|
||||
|
@ -91,6 +93,8 @@ TransactionFactory::GetNewTransaction(REFNSIID aTxnType, EditTxn **aResult)
|
|||
*aResult = new JoinElementTxn();
|
||||
else if (aTxnType.Equals(kEditAggregateTxnIID))
|
||||
*aResult = new EditAggregateTxn();
|
||||
else if (aTxnType.Equals(kPlaceholderTxnIID))
|
||||
*aResult = new PlaceholderTxn();
|
||||
else
|
||||
result = NS_ERROR_NO_INTERFACE;
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ CPPSRCS = \
|
|||
ChangeAttributeTxn.cpp \
|
||||
InsertTextTxn.cpp \
|
||||
DeleteTextTxn.cpp \
|
||||
PlaceholderTxn.cpp \
|
||||
CreateElementTxn.cpp \
|
||||
InsertElementTxn.cpp \
|
||||
DeleteElementTxn.cpp \
|
||||
|
@ -67,6 +68,7 @@ CPP_OBJS = \
|
|||
.\$(OBJDIR)\ChangeAttributeTxn.obj \
|
||||
.\$(OBJDIR)\InsertTextTxn.obj \
|
||||
.\$(OBJDIR)\DeleteTextTxn.obj \
|
||||
.\$(OBJDIR)\PlaceholderTxn.obj \
|
||||
.\$(OBJDIR)\CreateElementTxn.obj \
|
||||
.\$(OBJDIR)\InsertElementTxn.obj \
|
||||
.\$(OBJDIR)\DeleteElementTxn.obj \
|
||||
|
|
|
@ -1184,10 +1184,18 @@ NS_IMETHODIMP nsEditor::DeleteSelectionAndCreateNode(const nsString& aTag, nsIDO
|
|||
return result;
|
||||
}
|
||||
#ifdef NS_DEBUG
|
||||
PRBool testCollapsed;
|
||||
nsresult debugResult = selection->IsCollapsed(&testCollapsed);
|
||||
NS_ASSERTION((NS_SUCCEEDED(result)), "couldn't get a selection after deletion");
|
||||
NS_ASSERTION(PR_TRUE==testCollapsed, "selection not reset after deletion");;
|
||||
nsCOMPtr<nsIDOMNode>testSelectedNode;
|
||||
PRInt32 testOffset;
|
||||
nsresult debugResult = selection->GetAnchorNodeAndOffset(getter_AddRefs(testSelectedNode), &testOffset);
|
||||
// no selection is ok.
|
||||
// if there is a selection, it must be collapsed
|
||||
if (testSelectedNode)
|
||||
{
|
||||
PRBool testCollapsed;
|
||||
debugResult = selection->IsCollapsed(&testCollapsed);
|
||||
NS_ASSERTION((NS_SUCCEEDED(result)), "couldn't get a selection after deletion");
|
||||
NS_ASSERTION(PR_TRUE==testCollapsed, "selection not reset after deletion");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// split the text node
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#include "nsTextEditRules.h"
|
||||
#include "nsTextEditor.h"
|
||||
#include "PlaceholderTxn.h"
|
||||
#include "InsertTextTxn.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsIDOMElement.h"
|
||||
|
@ -31,6 +33,8 @@
|
|||
const static char* kMOZEditorBogusNodeAttr="MOZ_EDITOR_BOGUS_NODE";
|
||||
const static char* kMOZEditorBogusNodeValue="TRUE";
|
||||
|
||||
static NS_DEFINE_IID(kPlaceholderTxnIID, PLACEHOLDER_TXN_IID);
|
||||
|
||||
static PRBool NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag)
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement>element;
|
||||
|
@ -115,45 +119,12 @@ nsTextEditRules::WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel)
|
|||
*aCancel = PR_FALSE;
|
||||
|
||||
// check for the magic content node and delete it if it exists
|
||||
nsCOMPtr<nsIDOMDocument>doc;
|
||||
mEditor->GetDocument(getter_AddRefs(doc));
|
||||
nsCOMPtr<nsIDOMNodeList>nodeList;
|
||||
nsAutoString bodyTag = "body";
|
||||
nsresult result = doc->GetElementsByTagName(bodyTag, getter_AddRefs(nodeList));
|
||||
if ((NS_SUCCEEDED(result)) && nodeList)
|
||||
if (mBogusNode)
|
||||
{
|
||||
PRUint32 count;
|
||||
nodeList->GetLength(&count);
|
||||
NS_ASSERTION(1==count, "there is not exactly 1 body in the document!");
|
||||
nsCOMPtr<nsIDOMNode>bodyNode;
|
||||
result = nodeList->Item(0, getter_AddRefs(bodyNode));
|
||||
if ((NS_SUCCEEDED(result)) && bodyNode)
|
||||
{ // now we've got the body tag.
|
||||
// iterate the body tag, looking for editable content
|
||||
// if the magic node is found, delete it
|
||||
PRBool foundBogusContent=PR_TRUE;
|
||||
nsCOMPtr<nsIDOMNode>bodyChild; // a child of the body, for iteration
|
||||
nsCOMPtr<nsIDOMNode>bogusNode; // this will be the magic node
|
||||
result = bodyNode->GetFirstChild(getter_AddRefs(bodyChild));
|
||||
while ((NS_SUCCEEDED(result)) && bodyChild)
|
||||
{
|
||||
bogusNode = do_QueryInterface(bodyChild);
|
||||
if (PR_TRUE==IsEditable(bodyChild))
|
||||
{
|
||||
foundBogusContent = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode>temp;
|
||||
bodyChild->GetNextSibling(getter_AddRefs(temp));
|
||||
bodyChild = do_QueryInterface(temp);
|
||||
}
|
||||
if (PR_TRUE==foundBogusContent)
|
||||
{
|
||||
mEditor->DeleteNode(bogusNode);
|
||||
// there is no longer any legit selection, so clear it.
|
||||
aSelection->ClearSelection();
|
||||
}
|
||||
}
|
||||
mEditor->DeleteNode(mBogusNode);
|
||||
mBogusNode = do_QueryInterface(nsnull);
|
||||
// there is no longer any legit selection, so clear it.
|
||||
aSelection->ClearSelection();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -169,13 +140,22 @@ NS_IMETHODIMP
|
|||
nsTextEditRules::WillInsertText(nsIDOMSelection *aSelection,
|
||||
const nsString& aInputString,
|
||||
PRBool *aCancel,
|
||||
nsString& aOutputString)
|
||||
nsString& aOutputString,
|
||||
PlaceholderTxn **aTxn)
|
||||
{
|
||||
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
||||
// initialize out param
|
||||
*aCancel = PR_FALSE;
|
||||
// by default, we insert what we're told to insert
|
||||
aOutputString = aInputString;
|
||||
if (mBogusNode)
|
||||
{
|
||||
nsresult result = TransactionFactory::GetNewTransaction(kPlaceholderTxnIID, (EditTxn **)aTxn);
|
||||
if (NS_FAILED(result)) { return result; }
|
||||
if (!*aTxn) { return NS_ERROR_NULL_POINTER; }
|
||||
(*aTxn)->SetName(InsertTextTxn::gInsertTextTxnName);
|
||||
mEditor->Do(*aTxn);
|
||||
}
|
||||
return WillInsert(aSelection, aCancel);
|
||||
}
|
||||
|
||||
|
@ -315,31 +295,9 @@ nsTextEditRules::WillDeleteSelection(nsIDOMSelection *aSelection, PRBool *aCance
|
|||
*aCancel = PR_FALSE;
|
||||
|
||||
// if there is only bogus content, cancel the operation
|
||||
nsCOMPtr<nsIDOMNode>node;
|
||||
PRInt32 offset;
|
||||
nsresult result = aSelection->GetAnchorNodeAndOffset(getter_AddRefs(node), &offset);
|
||||
if ((NS_SUCCEEDED(result)) && node)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>parent;
|
||||
parent = do_QueryInterface(node);
|
||||
while (node)
|
||||
{ //if we find the bogus node, cancel the operation
|
||||
nsCOMPtr<nsIDOMElement>element;
|
||||
element = do_QueryInterface(parent);
|
||||
if (element)
|
||||
{
|
||||
nsAutoString att(kMOZEditorBogusNodeAttr);
|
||||
nsAutoString val;
|
||||
nsresult result = element->GetAttribute(att, val);
|
||||
if (val.Equals(kMOZEditorBogusNodeValue)) {
|
||||
*aCancel = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
// walk up the content hierarchy
|
||||
parent->GetParentNode(getter_AddRefs(node));
|
||||
parent = do_QueryInterface(node);
|
||||
}
|
||||
if (mBogusNode) {
|
||||
*aCancel = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -389,13 +347,13 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection, nsresult aResul
|
|||
}
|
||||
if (PR_TRUE==needsBogusContent)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>newPNode;
|
||||
// set mBogusNode to be the newly created <P>
|
||||
result = mEditor->CreateNode(nsAutoString("P"), bodyNode, 0,
|
||||
getter_AddRefs(newPNode));
|
||||
if ((NS_SUCCEEDED(result)) && newPNode)
|
||||
getter_AddRefs(mBogusNode));
|
||||
if ((NS_SUCCEEDED(result)) && mBogusNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>newTNode;
|
||||
result = mEditor->CreateNode(nsIEditor::GetTextNodeTag(), newPNode, 0,
|
||||
result = mEditor->CreateNode(nsIEditor::GetTextNodeTag(), mBogusNode, 0,
|
||||
getter_AddRefs(newTNode));
|
||||
if ((NS_SUCCEEDED(result)) && newTNode)
|
||||
{
|
||||
|
@ -411,7 +369,7 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection, nsresult aResul
|
|||
}
|
||||
// make sure we know the PNode is bogus
|
||||
nsCOMPtr<nsIDOMElement>newPElement;
|
||||
newPElement = do_QueryInterface(newPNode);
|
||||
newPElement = do_QueryInterface(mBogusNode);
|
||||
if (newPElement)
|
||||
{
|
||||
nsAutoString att(kMOZEditorBogusNodeAttr);
|
||||
|
|
|
@ -21,9 +21,10 @@
|
|||
|
||||
#include "nsIEditor.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDOMNode.h"
|
||||
|
||||
class nsTextEditor;
|
||||
|
||||
class PlaceholderTxn;
|
||||
|
||||
/** Object that encapsulates HTML text-specific editing rules.
|
||||
*
|
||||
|
@ -52,7 +53,8 @@ public:
|
|||
NS_IMETHOD WillInsertText(nsIDOMSelection *aSelection,
|
||||
const nsString& aInputString,
|
||||
PRBool *aCancel,
|
||||
nsString& aOutputString);
|
||||
nsString& aOutputString,
|
||||
PlaceholderTxn ** aTxn);
|
||||
NS_IMETHOD DidInsertText(nsIDOMSelection *aSelection, const nsString& aStringToInsert, nsresult aResult);
|
||||
|
||||
NS_IMETHOD WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel);
|
||||
|
@ -64,7 +66,7 @@ public:
|
|||
protected:
|
||||
|
||||
nsTextEditor *mEditor; // note that we do not refcount the editor
|
||||
|
||||
nsCOMPtr<nsIDOMNode> mBogusNode; // magic node acts as placeholder in empty doc
|
||||
};
|
||||
|
||||
#endif //nsTextEditRules_h__
|
||||
|
|
|
@ -49,6 +49,11 @@
|
|||
#include "nsIPresShell.h"
|
||||
#include "nsIStyleContext.h"
|
||||
|
||||
// transactions the text editor knows how to build itself
|
||||
#include "TransactionFactory.h"
|
||||
#include "PlaceholderTxn.h"
|
||||
#include "InsertTextTxn.h"
|
||||
|
||||
|
||||
class nsIFrame;
|
||||
|
||||
|
@ -430,22 +435,20 @@ NS_IMETHODIMP nsTextEditor::InsertText(const nsString& aStringToInsert)
|
|||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
PRBool cancel= PR_FALSE;
|
||||
|
||||
nsresult result = nsEditor::BeginTransaction();
|
||||
if (NS_FAILED(result)) { return result; }
|
||||
|
||||
// pre-process
|
||||
nsEditor::GetSelection(getter_AddRefs(selection));
|
||||
nsString stringToInsert;
|
||||
result = mRules->WillInsertText(selection, aStringToInsert, &cancel, stringToInsert);
|
||||
nsAutoString stringToInsert;
|
||||
PlaceholderTxn *placeholderTxn=nsnull;
|
||||
nsresult result = mRules->WillInsertText(selection, aStringToInsert, &cancel, stringToInsert,
|
||||
&placeholderTxn);
|
||||
if ((PR_FALSE==cancel) && (NS_SUCCEEDED(result)))
|
||||
{
|
||||
result = nsEditor::InsertText(stringToInsert);
|
||||
// post-process
|
||||
result = mRules->DidInsertText(selection, stringToInsert, result);
|
||||
}
|
||||
|
||||
nsresult endTxnResult = nsEditor::EndTransaction(); // don't return this result!
|
||||
NS_ASSERTION ((NS_SUCCEEDED(endTxnResult)), "bad end transaction result");
|
||||
if (placeholderTxn)
|
||||
placeholderTxn->SetAbsorb(PR_FALSE); // this ends the merging of txns into placeholderTxn
|
||||
|
||||
// BEGIN HACK!!!
|
||||
HACKForceRedraw();
|
||||
|
|
|
@ -167,7 +167,8 @@ NS_IMETHODIMP DeleteRangeTxn::Undo(void)
|
|||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
result = mEditor->GetSelection(getter_AddRefs(selection));
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
result = selection->Collapse(mStartParent, mStartOffset);
|
||||
selection->Collapse(mStartParent, mStartOffset);
|
||||
selection->Extend(mEndParent, mEndOffset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -153,26 +153,6 @@ NS_IMETHODIMP EditAggregateTxn::AppendChild(EditTxn *aTxn)
|
|||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP EditAggregateTxn::SetName(nsIAtom *aName)
|
||||
{
|
||||
mName = do_QueryInterface(aName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP EditAggregateTxn::GetName(nsIAtom **aName)
|
||||
{
|
||||
if (aName)
|
||||
{
|
||||
if (mName)
|
||||
{
|
||||
*aName = mName;
|
||||
NS_ADDREF(*aName);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP EditAggregateTxn::GetCount(PRInt32 *aCount)
|
||||
{
|
||||
if (!aCount) {
|
||||
|
@ -205,6 +185,28 @@ NS_IMETHODIMP EditAggregateTxn::GetTxnAt(PRInt32 aIndex, EditTxn **aTxn)
|
|||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP EditAggregateTxn::SetName(nsIAtom *aName)
|
||||
{
|
||||
mName = do_QueryInterface(aName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP EditAggregateTxn::GetName(nsIAtom **aName)
|
||||
{
|
||||
if (aName)
|
||||
{
|
||||
if (mName)
|
||||
{
|
||||
*aName = mName;
|
||||
NS_ADDREF(*aName);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -71,10 +71,10 @@ public:
|
|||
*/
|
||||
NS_IMETHOD GetTxnAt(PRInt32 aIndex, EditTxn **aTxn);
|
||||
|
||||
/** set the name assigned to this aggregate txn */
|
||||
/** set the name assigned to this txn */
|
||||
NS_IMETHOD SetName(nsIAtom *aName);
|
||||
|
||||
/** get the name assigned to this aggregate txn */
|
||||
/** get the name assigned to this txn */
|
||||
NS_IMETHOD GetName(nsIAtom **aName);
|
||||
|
||||
protected:
|
||||
|
@ -82,7 +82,6 @@ protected:
|
|||
//XXX: if this was an nsISupportsArray, it would handle refcounting for us
|
||||
nsVoidArray * mChildren;
|
||||
nsCOMPtr<nsIAtom> mName;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,8 +20,7 @@
|
|||
#define EditTxn_h__
|
||||
|
||||
#include "nsITransaction.h"
|
||||
|
||||
class nsIDOMNode;
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#define EDIT_TXN_IID \
|
||||
{/* c5ea31b0-ac48-11d2-86d8-000064657374 */ \
|
||||
|
@ -31,6 +30,8 @@ class nsIDOMNode;
|
|||
/**
|
||||
* base class for all document editing transactions.
|
||||
* provides default concrete behavior for all nsITransaction methods.
|
||||
* EditTxns optionally have a name. This name is for internal purposes only,
|
||||
* it is never seen by the user or by any external entity.
|
||||
*/
|
||||
class EditTxn : public nsITransaction
|
||||
{
|
||||
|
|
|
@ -119,19 +119,23 @@ NS_IMETHODIMP InsertTextTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransacti
|
|||
otherTxn->GetName(getter_AddRefs(txnName));
|
||||
if (txnName.get()==gInsertTextTxnName)
|
||||
{ // yep, it's one of ours. By definition, it must contain only
|
||||
// a single InsertTextTxn
|
||||
// another aggregate with a single child,
|
||||
// or a single InsertTextTxn
|
||||
nsCOMPtr<EditTxn> childTxn;
|
||||
otherTxn->GetTxnAt(0, getter_AddRefs(childTxn));
|
||||
nsCOMPtr<InsertTextTxn> otherInsertTxn;
|
||||
otherInsertTxn = do_QueryInterface(childTxn, &result);
|
||||
if (otherInsertTxn)
|
||||
if (childTxn)
|
||||
{
|
||||
if (PR_TRUE==IsSequentialInsert(otherInsertTxn))
|
||||
nsCOMPtr<InsertTextTxn> otherInsertTxn;
|
||||
otherInsertTxn = do_QueryInterface(childTxn, &result);
|
||||
if (otherInsertTxn)
|
||||
{
|
||||
nsAutoString otherData;
|
||||
otherInsertTxn->GetData(otherData);
|
||||
mStringToInsert += otherData;
|
||||
*aDidMerge = PR_TRUE;
|
||||
if (PR_TRUE==IsSequentialInsert(otherInsertTxn))
|
||||
{
|
||||
nsAutoString otherData;
|
||||
otherInsertTxn->GetData(otherData);
|
||||
mStringToInsert += otherData;
|
||||
*aDidMerge = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "PlaceholderTxn.h"
|
||||
#include "nsVoidArray.h"
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
static PRBool gNoisy = PR_TRUE;
|
||||
#else
|
||||
static const PRBool gNoisy = PR_FALSE;
|
||||
#endif
|
||||
|
||||
|
||||
PlaceholderTxn::PlaceholderTxn()
|
||||
: EditAggregateTxn()
|
||||
{
|
||||
mAbsorb=PR_TRUE;
|
||||
}
|
||||
|
||||
|
||||
PlaceholderTxn::~PlaceholderTxn()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP PlaceholderTxn::Do(void)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP PlaceholderTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransaction)
|
||||
{
|
||||
// set out param default value
|
||||
if (nsnull!=aDidMerge)
|
||||
*aDidMerge=PR_FALSE;
|
||||
nsresult result = NS_OK;
|
||||
if ((nsnull!=aDidMerge) && (nsnull!=aTransaction))
|
||||
{
|
||||
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;
|
||||
}
|
||||
else
|
||||
{ // let our last child txn make the choice
|
||||
PRInt32 count = mChildren->Count();
|
||||
if (0<count)
|
||||
{
|
||||
EditTxn *lastTxn = (EditTxn*)(mChildren->ElementAt(count-1));
|
||||
if (lastTxn)
|
||||
{
|
||||
lastTxn->Merge(aDidMerge, aTransaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef AggregatePlaceholderTxn_h__
|
||||
#define AggregatePlaceholderTxn_h__
|
||||
|
||||
#include "EditAggregateTxn.h"
|
||||
|
||||
#define PLACEHOLDER_TXN_IID \
|
||||
{/* {0CE9FB00-D9D1-11d2-86DE-000064657374} */ \
|
||||
0x0CE9FB00, 0xD9D1, 0x11d2, \
|
||||
{0x86, 0xde, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
public:
|
||||
|
||||
private:
|
||||
PlaceholderTxn();
|
||||
|
||||
public:
|
||||
|
||||
virtual ~PlaceholderTxn();
|
||||
|
||||
NS_IMETHOD Do(void);
|
||||
|
||||
NS_IMETHOD Merge(PRBool *aDidMerge, nsITransaction *aTransaction);
|
||||
|
||||
NS_IMETHOD SetAbsorb(PRBool aAbsorb);
|
||||
|
||||
friend class TransactionFactory;
|
||||
|
||||
protected:
|
||||
|
||||
PRBool mAbsorb;
|
||||
|
||||
};
|
||||
|
||||
inline NS_IMETHODIMP PlaceholderTxn::SetAbsorb(PRBool aAbsorb)
|
||||
{
|
||||
mAbsorb = aAbsorb;
|
||||
return NS_OK;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -19,6 +19,7 @@
|
|||
#include "TransactionFactory.h"
|
||||
// transactions this factory knows how to build
|
||||
#include "EditAggregateTxn.h"
|
||||
#include "PlaceholderTxn.h"
|
||||
#include "InsertTextTxn.h"
|
||||
#include "DeleteTextTxn.h"
|
||||
#include "CreateElementTxn.h"
|
||||
|
@ -39,6 +40,7 @@
|
|||
#include "JoinTableCellsTxn.h"
|
||||
|
||||
static NS_DEFINE_IID(kEditAggregateTxnIID, EDIT_AGGREGATE_TXN_IID);
|
||||
static NS_DEFINE_IID(kPlaceholderTxnIID, PLACEHOLDER_TXN_IID);
|
||||
static NS_DEFINE_IID(kInsertTextTxnIID, INSERT_TEXT_TXN_IID);
|
||||
static NS_DEFINE_IID(kDeleteTextTxnIID, DELETE_TEXT_TXN_IID);
|
||||
static NS_DEFINE_IID(kCreateElementTxnIID, CREATE_ELEMENT_TXN_IID);
|
||||
|
@ -91,6 +93,8 @@ TransactionFactory::GetNewTransaction(REFNSIID aTxnType, EditTxn **aResult)
|
|||
*aResult = new JoinElementTxn();
|
||||
else if (aTxnType.Equals(kEditAggregateTxnIID))
|
||||
*aResult = new EditAggregateTxn();
|
||||
else if (aTxnType.Equals(kPlaceholderTxnIID))
|
||||
*aResult = new PlaceholderTxn();
|
||||
else
|
||||
result = NS_ERROR_NO_INTERFACE;
|
||||
|
||||
|
|
|
@ -1184,10 +1184,18 @@ NS_IMETHODIMP nsEditor::DeleteSelectionAndCreateNode(const nsString& aTag, nsIDO
|
|||
return result;
|
||||
}
|
||||
#ifdef NS_DEBUG
|
||||
PRBool testCollapsed;
|
||||
nsresult debugResult = selection->IsCollapsed(&testCollapsed);
|
||||
NS_ASSERTION((NS_SUCCEEDED(result)), "couldn't get a selection after deletion");
|
||||
NS_ASSERTION(PR_TRUE==testCollapsed, "selection not reset after deletion");;
|
||||
nsCOMPtr<nsIDOMNode>testSelectedNode;
|
||||
PRInt32 testOffset;
|
||||
nsresult debugResult = selection->GetAnchorNodeAndOffset(getter_AddRefs(testSelectedNode), &testOffset);
|
||||
// no selection is ok.
|
||||
// if there is a selection, it must be collapsed
|
||||
if (testSelectedNode)
|
||||
{
|
||||
PRBool testCollapsed;
|
||||
debugResult = selection->IsCollapsed(&testCollapsed);
|
||||
NS_ASSERTION((NS_SUCCEEDED(result)), "couldn't get a selection after deletion");
|
||||
NS_ASSERTION(PR_TRUE==testCollapsed, "selection not reset after deletion");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// split the text node
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#include "nsTextEditRules.h"
|
||||
#include "nsTextEditor.h"
|
||||
#include "PlaceholderTxn.h"
|
||||
#include "InsertTextTxn.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsIDOMElement.h"
|
||||
|
@ -31,6 +33,8 @@
|
|||
const static char* kMOZEditorBogusNodeAttr="MOZ_EDITOR_BOGUS_NODE";
|
||||
const static char* kMOZEditorBogusNodeValue="TRUE";
|
||||
|
||||
static NS_DEFINE_IID(kPlaceholderTxnIID, PLACEHOLDER_TXN_IID);
|
||||
|
||||
static PRBool NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag)
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement>element;
|
||||
|
@ -115,45 +119,12 @@ nsTextEditRules::WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel)
|
|||
*aCancel = PR_FALSE;
|
||||
|
||||
// check for the magic content node and delete it if it exists
|
||||
nsCOMPtr<nsIDOMDocument>doc;
|
||||
mEditor->GetDocument(getter_AddRefs(doc));
|
||||
nsCOMPtr<nsIDOMNodeList>nodeList;
|
||||
nsAutoString bodyTag = "body";
|
||||
nsresult result = doc->GetElementsByTagName(bodyTag, getter_AddRefs(nodeList));
|
||||
if ((NS_SUCCEEDED(result)) && nodeList)
|
||||
if (mBogusNode)
|
||||
{
|
||||
PRUint32 count;
|
||||
nodeList->GetLength(&count);
|
||||
NS_ASSERTION(1==count, "there is not exactly 1 body in the document!");
|
||||
nsCOMPtr<nsIDOMNode>bodyNode;
|
||||
result = nodeList->Item(0, getter_AddRefs(bodyNode));
|
||||
if ((NS_SUCCEEDED(result)) && bodyNode)
|
||||
{ // now we've got the body tag.
|
||||
// iterate the body tag, looking for editable content
|
||||
// if the magic node is found, delete it
|
||||
PRBool foundBogusContent=PR_TRUE;
|
||||
nsCOMPtr<nsIDOMNode>bodyChild; // a child of the body, for iteration
|
||||
nsCOMPtr<nsIDOMNode>bogusNode; // this will be the magic node
|
||||
result = bodyNode->GetFirstChild(getter_AddRefs(bodyChild));
|
||||
while ((NS_SUCCEEDED(result)) && bodyChild)
|
||||
{
|
||||
bogusNode = do_QueryInterface(bodyChild);
|
||||
if (PR_TRUE==IsEditable(bodyChild))
|
||||
{
|
||||
foundBogusContent = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode>temp;
|
||||
bodyChild->GetNextSibling(getter_AddRefs(temp));
|
||||
bodyChild = do_QueryInterface(temp);
|
||||
}
|
||||
if (PR_TRUE==foundBogusContent)
|
||||
{
|
||||
mEditor->DeleteNode(bogusNode);
|
||||
// there is no longer any legit selection, so clear it.
|
||||
aSelection->ClearSelection();
|
||||
}
|
||||
}
|
||||
mEditor->DeleteNode(mBogusNode);
|
||||
mBogusNode = do_QueryInterface(nsnull);
|
||||
// there is no longer any legit selection, so clear it.
|
||||
aSelection->ClearSelection();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -169,13 +140,22 @@ NS_IMETHODIMP
|
|||
nsTextEditRules::WillInsertText(nsIDOMSelection *aSelection,
|
||||
const nsString& aInputString,
|
||||
PRBool *aCancel,
|
||||
nsString& aOutputString)
|
||||
nsString& aOutputString,
|
||||
PlaceholderTxn **aTxn)
|
||||
{
|
||||
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
|
||||
// initialize out param
|
||||
*aCancel = PR_FALSE;
|
||||
// by default, we insert what we're told to insert
|
||||
aOutputString = aInputString;
|
||||
if (mBogusNode)
|
||||
{
|
||||
nsresult result = TransactionFactory::GetNewTransaction(kPlaceholderTxnIID, (EditTxn **)aTxn);
|
||||
if (NS_FAILED(result)) { return result; }
|
||||
if (!*aTxn) { return NS_ERROR_NULL_POINTER; }
|
||||
(*aTxn)->SetName(InsertTextTxn::gInsertTextTxnName);
|
||||
mEditor->Do(*aTxn);
|
||||
}
|
||||
return WillInsert(aSelection, aCancel);
|
||||
}
|
||||
|
||||
|
@ -315,31 +295,9 @@ nsTextEditRules::WillDeleteSelection(nsIDOMSelection *aSelection, PRBool *aCance
|
|||
*aCancel = PR_FALSE;
|
||||
|
||||
// if there is only bogus content, cancel the operation
|
||||
nsCOMPtr<nsIDOMNode>node;
|
||||
PRInt32 offset;
|
||||
nsresult result = aSelection->GetAnchorNodeAndOffset(getter_AddRefs(node), &offset);
|
||||
if ((NS_SUCCEEDED(result)) && node)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>parent;
|
||||
parent = do_QueryInterface(node);
|
||||
while (node)
|
||||
{ //if we find the bogus node, cancel the operation
|
||||
nsCOMPtr<nsIDOMElement>element;
|
||||
element = do_QueryInterface(parent);
|
||||
if (element)
|
||||
{
|
||||
nsAutoString att(kMOZEditorBogusNodeAttr);
|
||||
nsAutoString val;
|
||||
nsresult result = element->GetAttribute(att, val);
|
||||
if (val.Equals(kMOZEditorBogusNodeValue)) {
|
||||
*aCancel = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
// walk up the content hierarchy
|
||||
parent->GetParentNode(getter_AddRefs(node));
|
||||
parent = do_QueryInterface(node);
|
||||
}
|
||||
if (mBogusNode) {
|
||||
*aCancel = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -389,13 +347,13 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection, nsresult aResul
|
|||
}
|
||||
if (PR_TRUE==needsBogusContent)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>newPNode;
|
||||
// set mBogusNode to be the newly created <P>
|
||||
result = mEditor->CreateNode(nsAutoString("P"), bodyNode, 0,
|
||||
getter_AddRefs(newPNode));
|
||||
if ((NS_SUCCEEDED(result)) && newPNode)
|
||||
getter_AddRefs(mBogusNode));
|
||||
if ((NS_SUCCEEDED(result)) && mBogusNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>newTNode;
|
||||
result = mEditor->CreateNode(nsIEditor::GetTextNodeTag(), newPNode, 0,
|
||||
result = mEditor->CreateNode(nsIEditor::GetTextNodeTag(), mBogusNode, 0,
|
||||
getter_AddRefs(newTNode));
|
||||
if ((NS_SUCCEEDED(result)) && newTNode)
|
||||
{
|
||||
|
@ -411,7 +369,7 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection, nsresult aResul
|
|||
}
|
||||
// make sure we know the PNode is bogus
|
||||
nsCOMPtr<nsIDOMElement>newPElement;
|
||||
newPElement = do_QueryInterface(newPNode);
|
||||
newPElement = do_QueryInterface(mBogusNode);
|
||||
if (newPElement)
|
||||
{
|
||||
nsAutoString att(kMOZEditorBogusNodeAttr);
|
||||
|
|
|
@ -21,9 +21,10 @@
|
|||
|
||||
#include "nsIEditor.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDOMNode.h"
|
||||
|
||||
class nsTextEditor;
|
||||
|
||||
class PlaceholderTxn;
|
||||
|
||||
/** Object that encapsulates HTML text-specific editing rules.
|
||||
*
|
||||
|
@ -52,7 +53,8 @@ public:
|
|||
NS_IMETHOD WillInsertText(nsIDOMSelection *aSelection,
|
||||
const nsString& aInputString,
|
||||
PRBool *aCancel,
|
||||
nsString& aOutputString);
|
||||
nsString& aOutputString,
|
||||
PlaceholderTxn ** aTxn);
|
||||
NS_IMETHOD DidInsertText(nsIDOMSelection *aSelection, const nsString& aStringToInsert, nsresult aResult);
|
||||
|
||||
NS_IMETHOD WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel);
|
||||
|
@ -64,7 +66,7 @@ public:
|
|||
protected:
|
||||
|
||||
nsTextEditor *mEditor; // note that we do not refcount the editor
|
||||
|
||||
nsCOMPtr<nsIDOMNode> mBogusNode; // magic node acts as placeholder in empty doc
|
||||
};
|
||||
|
||||
#endif //nsTextEditRules_h__
|
||||
|
|
Загрузка…
Ссылка в новой задаче