mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
bug 66290: embedding work: refactor editor to allow smaller plaintext only library. Embedding clients may be interested inthis library if they want to embed a browser but not composer/mail-compose. Reduces library footprint for plaintext-only library by over 50% on all three platforms. r=fm; sr=kin
This commit is contained in:
parent
4745f05247
commit
fb60392b41
@ -31,50 +31,83 @@ LIBRARY_NAME = editor
|
||||
IS_COMPONENT = 1
|
||||
REQUIRES = xpcom dom js locale layout uriloader widget txmgr htmlparser necko pref view appshell rdf webshell timer txtsvc intl lwbrk docshell chrome caps appcomps
|
||||
|
||||
CPPSRCS = \
|
||||
nsEditor.cpp \
|
||||
nsEditorService.cpp \
|
||||
nsEditorController.cpp \
|
||||
nsEditorCommands.cpp \
|
||||
nsComposerCommands.cpp \
|
||||
nsEditorUtils.cpp \
|
||||
nsEditorRegistration.cpp \
|
||||
nsEditorParserObserver.cpp \
|
||||
nsTextEditRules.cpp \
|
||||
nsHTMLEditUtils.cpp \
|
||||
TextEditorTest.cpp \
|
||||
nsHTMLEditRules.cpp \
|
||||
nsEditorEventListeners.cpp \
|
||||
nsEditorShellMouseListener.cpp \
|
||||
nsEditProperty.cpp \
|
||||
nsHTMLEditor.cpp \
|
||||
ChangeAttributeTxn.cpp \
|
||||
EditTxn.cpp \
|
||||
EditAggregateTxn.cpp \
|
||||
nsTableEditor.cpp \
|
||||
InsertTextTxn.cpp \
|
||||
PlaceholderTxn.cpp \
|
||||
DeleteTextTxn.cpp \
|
||||
CreateElementTxn.cpp \
|
||||
InsertElementTxn.cpp \
|
||||
DeleteElementTxn.cpp \
|
||||
DeleteRangeTxn.cpp \
|
||||
SplitElementTxn.cpp \
|
||||
JoinElementTxn.cpp \
|
||||
nsStyleSheetTxns.cpp \
|
||||
TransactionFactory.cpp \
|
||||
TypeInState.cpp \
|
||||
nsInternetCiter.cpp \
|
||||
nsAOLCiter.cpp \
|
||||
nsWrapUtils.cpp \
|
||||
nsInterfaceState.cpp \
|
||||
nsEditorShell.cpp \
|
||||
IMETextTxn.cpp \
|
||||
IMECommitTxn.cpp \
|
||||
nsHTMLEditorLog.cpp \
|
||||
nsEditorTxnLog.cpp \
|
||||
CPPSRCS = \
|
||||
ChangeAttributeTxn.cpp \
|
||||
CreateElementTxn.cpp \
|
||||
DeleteElementTxn.cpp \
|
||||
DeleteRangeTxn.cpp \
|
||||
DeleteTextTxn.cpp \
|
||||
EditAggregateTxn.cpp \
|
||||
EditTxn.cpp \
|
||||
IMECommitTxn.cpp \
|
||||
IMETextTxn.cpp \
|
||||
InsertElementTxn.cpp \
|
||||
InsertTextTxn.cpp \
|
||||
JoinElementTxn.cpp \
|
||||
nsComposerCommands.cpp \
|
||||
nsEditorCommands.cpp \
|
||||
nsEditorController.cpp \
|
||||
nsEditor.cpp \
|
||||
nsEditorEventListeners.cpp \
|
||||
nsEditorUtils.cpp \
|
||||
nsEditProperty.cpp \
|
||||
nsHTMLEditUtils.cpp \
|
||||
nsPlaintextDataTransfer.cpp \
|
||||
nsPlaintextEditor.cpp \
|
||||
nsSelectionState.cpp \
|
||||
nsStyleSheetTxns.cpp \
|
||||
nsTextEditRules.cpp \
|
||||
PlaceholderTxn.cpp \
|
||||
SplitElementTxn.cpp \
|
||||
TransactionFactory.cpp \
|
||||
$(NULL)
|
||||
|
||||
# MOZ_BUILD_PLAINTEXT_EDITOR_CORE_ONLY=1
|
||||
|
||||
ifdef MOZ_BUILD_PLAINTEXT_EDITOR_CORE_ONLY
|
||||
|
||||
# We're only building the Core PlainText Editor Source so just include
|
||||
# the plain text registration file.
|
||||
|
||||
CPPSRCS += nsTextEditorReg.cpp
|
||||
|
||||
else
|
||||
|
||||
# Building the full blown HTML Editor so add it's source files and objects:
|
||||
|
||||
CPPSRCS += nsAOLCiter.cpp \
|
||||
nsEditorParserObserver.cpp \
|
||||
nsEditorRegistration.cpp \
|
||||
nsEditorShell.cpp \
|
||||
nsEditorShellMouseListener.cpp \
|
||||
nsEditorService.cpp \
|
||||
nsHTMLDataTransfer.cpp \
|
||||
nsHTMLEditor.cpp \
|
||||
nsHTMLEditorStyle.cpp \
|
||||
nsHTMLEditRules.cpp \
|
||||
nsInterfaceState.cpp \
|
||||
nsInternetCiter.cpp \
|
||||
nsTableEditor.cpp \
|
||||
nsWrapUtils.cpp \
|
||||
TextEditorTest.cpp \
|
||||
TypeInState.cpp \
|
||||
$(NULL)
|
||||
|
||||
# Enable Editor API Logging!
|
||||
ENABLE_EDITOR_API_LOG=1
|
||||
|
||||
ifdef ENABLE_EDITOR_API_LOG
|
||||
|
||||
CPPSRCS += nsHTMLEditorLog.cpp \
|
||||
nsEditorTxnLog.cpp \
|
||||
$(NULL)
|
||||
|
||||
DEFINES += -DENABLE_EDITOR_API_LOG
|
||||
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
EXTRA_DSO_LDOPTS = \
|
||||
$(MOZ_NECKO_UTIL_LIBS) \
|
||||
$(MOZ_COMPONENT_LIBS) \
|
||||
@ -83,5 +116,3 @@ EXTRA_DSO_LDOPTS = \
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
DEFINES += -DENABLE_EDITOR_API_LOG
|
||||
|
||||
|
@ -25,95 +25,127 @@ include <$(DEPTH)/config/config.mak>
|
||||
|
||||
LIBRARY_NAME=editor
|
||||
|
||||
CPPSRCS = \
|
||||
nsEditor.cpp \
|
||||
nsEditorService.cpp \
|
||||
nsEditorController.cpp \
|
||||
nsEditorCommands.cpp \
|
||||
nsComposerCommands.cpp \
|
||||
nsEditorUtils.cpp \
|
||||
nsEditorRegistration.cpp \
|
||||
nsEditorParserObserver.cpp \
|
||||
nsTextEditRules.cpp \
|
||||
nsHTMLEditRules.cpp \
|
||||
nsHTMLEditUtils.cpp \
|
||||
TextEditorTest.cpp \
|
||||
nsEditorEventListeners.cpp \
|
||||
nsEditorShellMouseListener.cpp \
|
||||
nsEditProperty.cpp \
|
||||
EditTxn.cpp \
|
||||
EditAggregateTxn.cpp \
|
||||
ChangeAttributeTxn.cpp \
|
||||
InsertTextTxn.cpp \
|
||||
DeleteTextTxn.cpp \
|
||||
PlaceholderTxn.cpp \
|
||||
CreateElementTxn.cpp \
|
||||
InsertElementTxn.cpp \
|
||||
DeleteElementTxn.cpp \
|
||||
DeleteRangeTxn.cpp \
|
||||
SplitElementTxn.cpp \
|
||||
JoinElementTxn.cpp \
|
||||
nsStyleSheetTxns.cpp \
|
||||
TransactionFactory.cpp \
|
||||
TypeInState.cpp \
|
||||
nsHTMLEditor.cpp \
|
||||
nsTableEditor.cpp \
|
||||
nsInternetCiter.cpp \
|
||||
nsAOLCiter.cpp \
|
||||
nsWrapUtils.cpp \
|
||||
nsInterfaceState.cpp \
|
||||
nsEditorShell.cpp \
|
||||
IMETextTxn.cpp \
|
||||
IMECommitTxn.cpp \
|
||||
$(NULL)
|
||||
# Uncomment the line below, or define MOZ_BUILD_PLAINTEXT_EDITOR_CORE_ONLY
|
||||
# in your environment, to build only the plain text editor core files:
|
||||
# MOZ_BUILD_PLAINTEXT_EDITOR_CORE_ONLY=1
|
||||
|
||||
CPP_OBJS = \
|
||||
.\$(OBJDIR)\nsEditor.obj \
|
||||
.\$(OBJDIR)\nsEditorService.obj \
|
||||
.\$(OBJDIR)\nsEditorController.obj \
|
||||
.\$(OBJDIR)\nsEditorCommands.obj \
|
||||
.\$(OBJDIR)\nsComposerCommands.obj \
|
||||
.\$(OBJDIR)\nsEditorUtils.obj \
|
||||
.\$(OBJDIR)\nsEditorRegistration.obj \
|
||||
.\$(OBJDIR)\nsEditorParserObserver.obj \
|
||||
.\$(OBJDIR)\nsTextEditRules.obj \
|
||||
.\$(OBJDIR)\TextEditorTest.obj \
|
||||
.\$(OBJDIR)\nsHTMLEditRules.obj \
|
||||
.\$(OBJDIR)\nsHTMLEditUtils.obj \
|
||||
.\$(OBJDIR)\nsEditorEventListeners.obj \
|
||||
.\$(OBJDIR)\nsEditorShellMouseListener.obj \
|
||||
.\$(OBJDIR)\nsEditProperty.obj \
|
||||
.\$(OBJDIR)\EditTxn.obj \
|
||||
.\$(OBJDIR)\EditAggregateTxn.obj \
|
||||
.\$(OBJDIR)\ChangeAttributeTxn.obj \
|
||||
.\$(OBJDIR)\InsertTextTxn.obj \
|
||||
.\$(OBJDIR)\DeleteTextTxn.obj \
|
||||
.\$(OBJDIR)\PlaceholderTxn.obj \
|
||||
.\$(OBJDIR)\CreateElementTxn.obj \
|
||||
.\$(OBJDIR)\InsertElementTxn.obj \
|
||||
.\$(OBJDIR)\DeleteElementTxn.obj \
|
||||
.\$(OBJDIR)\DeleteRangeTxn.obj \
|
||||
.\$(OBJDIR)\SplitElementTxn.obj \
|
||||
.\$(OBJDIR)\JoinElementTxn.obj \
|
||||
.\$(OBJDIR)\nsStyleSheetTxns.obj \
|
||||
.\$(OBJDIR)\TransactionFactory.obj \
|
||||
.\$(OBJDIR)\TypeInState.obj \
|
||||
.\$(OBJDIR)\nsHTMLEditor.obj \
|
||||
.\$(OBJDIR)\nsTableEditor.obj \
|
||||
.\$(OBJDIR)\nsInternetCiter.obj \
|
||||
.\$(OBJDIR)\nsAOLCiter.obj \
|
||||
.\$(OBJDIR)\nsWrapUtils.obj \
|
||||
.\$(OBJDIR)\nsInterfaceState.obj \
|
||||
.\$(OBJDIR)\nsEditorShell.obj \
|
||||
.\$(OBJDIR)\IMETextTxn.obj \
|
||||
.\$(OBJDIR)\IMECommitTxn.obj \
|
||||
$(NULL)
|
||||
# Editor Core Source Files and Objects:
|
||||
|
||||
MODULE=editor
|
||||
CPPSRCS = \
|
||||
ChangeAttributeTxn.cpp \
|
||||
CreateElementTxn.cpp \
|
||||
DeleteElementTxn.cpp \
|
||||
DeleteRangeTxn.cpp \
|
||||
DeleteTextTxn.cpp \
|
||||
EditAggregateTxn.cpp \
|
||||
EditTxn.cpp \
|
||||
IMECommitTxn.cpp \
|
||||
IMETextTxn.cpp \
|
||||
InsertElementTxn.cpp \
|
||||
InsertTextTxn.cpp \
|
||||
JoinElementTxn.cpp \
|
||||
nsComposerCommands.cpp \
|
||||
nsEditorCommands.cpp \
|
||||
nsEditorController.cpp \
|
||||
nsEditor.cpp \
|
||||
nsEditorEventListeners.cpp \
|
||||
nsEditorUtils.cpp \
|
||||
nsEditProperty.cpp \
|
||||
nsHTMLEditUtils.cpp \
|
||||
nsPlaintextDataTransfer.cpp \
|
||||
nsPlaintextEditor.cpp \
|
||||
nsSelectionState.cpp \
|
||||
nsStyleSheetTxns.cpp \
|
||||
nsTextEditRules.cpp \
|
||||
PlaceholderTxn.cpp \
|
||||
SplitElementTxn.cpp \
|
||||
TransactionFactory.cpp \
|
||||
$(NULL)
|
||||
|
||||
MAKE_OBJ_TYPE = DLL
|
||||
DLLNAME = editor
|
||||
DLL=.\$(OBJDIR)\$(DLLNAME).dll
|
||||
CPP_OBJS = \
|
||||
.\$(OBJDIR)\ChangeAttributeTxn.obj \
|
||||
.\$(OBJDIR)\CreateElementTxn.obj \
|
||||
.\$(OBJDIR)\DeleteElementTxn.obj \
|
||||
.\$(OBJDIR)\DeleteRangeTxn.obj \
|
||||
.\$(OBJDIR)\DeleteTextTxn.obj \
|
||||
.\$(OBJDIR)\EditAggregateTxn.obj \
|
||||
.\$(OBJDIR)\EditTxn.obj \
|
||||
.\$(OBJDIR)\IMECommitTxn.obj \
|
||||
.\$(OBJDIR)\IMETextTxn.obj \
|
||||
.\$(OBJDIR)\InsertElementTxn.obj \
|
||||
.\$(OBJDIR)\InsertTextTxn.obj \
|
||||
.\$(OBJDIR)\JoinElementTxn.obj \
|
||||
.\$(OBJDIR)\nsComposerCommands.obj \
|
||||
.\$(OBJDIR)\nsEditorCommands.obj \
|
||||
.\$(OBJDIR)\nsEditorController.obj \
|
||||
.\$(OBJDIR)\nsEditorEventListeners.obj \
|
||||
.\$(OBJDIR)\nsEditor.obj \
|
||||
.\$(OBJDIR)\nsEditorUtils.obj \
|
||||
.\$(OBJDIR)\nsEditProperty.obj \
|
||||
.\$(OBJDIR)\nsHTMLEditUtils.obj \
|
||||
.\$(OBJDIR)\nsPlaintextDataTransfer.obj \
|
||||
.\$(OBJDIR)\nsPlaintextEditor.obj \
|
||||
.\$(OBJDIR)\nsSelectionState.obj \
|
||||
.\$(OBJDIR)\nsStyleSheetTxns.obj \
|
||||
.\$(OBJDIR)\nsTextEditRules.obj \
|
||||
.\$(OBJDIR)\PlaceholderTxn.obj \
|
||||
.\$(OBJDIR)\SplitElementTxn.obj \
|
||||
.\$(OBJDIR)\TransactionFactory.obj \
|
||||
$(NULL)
|
||||
|
||||
!if defined(MOZ_BUILD_PLAINTEXT_EDITOR_CORE_ONLY)
|
||||
|
||||
# We're only building the Core PlainText Editor Source so just include
|
||||
# the plain text registration file.
|
||||
|
||||
CPPSRCS = $(CPPSRCS) \
|
||||
nsTextEditorReg.cpp \
|
||||
$(NULL)
|
||||
|
||||
CPP_OBJS = $(CPP_OBJS) \
|
||||
.\$(OBJDIR)\nsTextEditorReg.obj \
|
||||
$(NULL)
|
||||
!else
|
||||
|
||||
# Building the full blown HTML Editor so add it's source files and objects:
|
||||
|
||||
CPPSRCS = $(CPPSRCS) \
|
||||
nsAOLCiter.cpp \
|
||||
nsEditorParserObserver.cpp \
|
||||
nsEditorRegistration.cpp \
|
||||
nsEditorService.cpp \
|
||||
nsEditorShell.cpp \
|
||||
nsEditorShellMouseListener.cpp \
|
||||
nsHTMLDataTransfer.cpp \
|
||||
nsHTMLEditor.cpp \
|
||||
nsHTMLEditorStyle.cpp \
|
||||
nsHTMLEditRules.cpp \
|
||||
nsInterfaceState.cpp \
|
||||
nsInternetCiter.cpp \
|
||||
nsTableEditor.cpp \
|
||||
nsWrapUtils.cpp \
|
||||
TextEditorTest.cpp \
|
||||
TypeInState.cpp \
|
||||
$(NULL)
|
||||
|
||||
CPP_OBJS = $(CPP_OBJS) \
|
||||
.\$(OBJDIR)\nsAOLCiter.obj \
|
||||
.\$(OBJDIR)\nsEditorParserObserver.obj \
|
||||
.\$(OBJDIR)\nsEditorRegistration.obj \
|
||||
.\$(OBJDIR)\nsEditorService.obj \
|
||||
.\$(OBJDIR)\nsEditorShellMouseListener.obj \
|
||||
.\$(OBJDIR)\nsEditorShell.obj \
|
||||
.\$(OBJDIR)\nsHTMLDataTransfer.obj \
|
||||
.\$(OBJDIR)\nsHTMLEditor.obj \
|
||||
.\$(OBJDIR)\nsHTMLEditorStyle.obj \
|
||||
.\$(OBJDIR)\nsHTMLEditRules.obj \
|
||||
.\$(OBJDIR)\nsInterfaceState.obj \
|
||||
.\$(OBJDIR)\nsInternetCiter.obj \
|
||||
.\$(OBJDIR)\nsTableEditor.obj \
|
||||
.\$(OBJDIR)\nsWrapUtils.obj \
|
||||
.\$(OBJDIR)\TextEditorTest.obj \
|
||||
.\$(OBJDIR)\TypeInState.obj \
|
||||
$(NULL)
|
||||
|
||||
# Enable Editor API Logging!
|
||||
ENABLE_EDITOR_API_LOG=1
|
||||
@ -122,17 +154,26 @@ ENABLE_EDITOR_API_LOG=1
|
||||
CPPSRCS = $(CPPSRCS) \
|
||||
nsHTMLEditorLog.cpp \
|
||||
nsEditorTxnLog.cpp \
|
||||
$(NULL)
|
||||
$(NULL)
|
||||
|
||||
CPP_OBJS = $(CPP_OBJS) \
|
||||
.\$(OBJDIR)\nsHTMLEditorLog.obj \
|
||||
.\$(OBJDIR)\nsEditorTxnLog.obj \
|
||||
$(NULL)
|
||||
$(NULL)
|
||||
|
||||
DEFINES = -DENABLE_EDITOR_API_LOG $(DEFINES)
|
||||
|
||||
!endif
|
||||
|
||||
!endif
|
||||
|
||||
MODULE=editor
|
||||
|
||||
MAKE_OBJ_TYPE = DLL
|
||||
DLLNAME = editor
|
||||
DLL=.\$(OBJDIR)\$(DLLNAME).dll
|
||||
|
||||
|
||||
LCFLAGS = \
|
||||
$(LCFLAGS) \
|
||||
$(DEFINES) \
|
||||
|
@ -28,7 +28,7 @@
|
||||
0xa6cf911d, 0x15b3, 0x11d2, \
|
||||
{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} }
|
||||
|
||||
class nsHTMLEditor;
|
||||
class nsPlaintextEditor;
|
||||
class nsISelection;
|
||||
|
||||
/***************************************************************************
|
||||
@ -57,7 +57,7 @@ public:
|
||||
//Interfaces for addref and release and queryinterface
|
||||
//NOTE: Use NS_DECL_ISUPPORTS_INHERITED in any class inherited from nsIEditRules
|
||||
|
||||
NS_IMETHOD Init(nsHTMLEditor *aEditor, PRUint32 aFlags)=0;
|
||||
NS_IMETHOD Init(nsPlaintextEditor *aEditor, PRUint32 aFlags)=0;
|
||||
NS_IMETHOD BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection)=0;
|
||||
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)=0;
|
||||
NS_IMETHOD WillDoAction(nsISelection *aSelection, nsRulesInfo *aInfo, PRBool *aCancel, PRBool *aHandled)=0;
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include "nsIKBStateControl.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsIScrollbar.h"
|
||||
#include "nsIPlaintextEditor.h"
|
||||
|
||||
#include "nsIFrame.h" // Needed by IME code
|
||||
|
||||
@ -93,7 +94,7 @@
|
||||
#include "JoinElementTxn.h"
|
||||
#include "nsStyleSheetTxns.h"
|
||||
#include "IMETextTxn.h"
|
||||
#include "nsIHTMLEditor.h"
|
||||
|
||||
// included for nsEditor::CreateHTMLContent
|
||||
#include "nsIElementFactory.h"
|
||||
#include "nsINodeInfo.h"
|
||||
@ -148,738 +149,6 @@ const PRUnichar nbsp = 160;
|
||||
PRInt32 nsEditor::gInstanceCount = 0;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* class for recording selection info. stores selection as collection of
|
||||
* { {startnode, startoffset} , {endnode, endoffset} } tuples. Cant store
|
||||
* ranges since dom gravity will possibly change the ranges.
|
||||
*/
|
||||
nsSelectionState::nsSelectionState() : mArray(){}
|
||||
|
||||
nsSelectionState::~nsSelectionState()
|
||||
{
|
||||
MakeEmpty();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSelectionState::SaveSelection(nsISelection *aSel)
|
||||
{
|
||||
if (!aSel) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
PRInt32 i,rangeCount, arrayCount = mArray.Count();
|
||||
nsRangeStore *item;
|
||||
aSel->GetRangeCount(&rangeCount);
|
||||
|
||||
// if we need more items in the array, new them
|
||||
if (arrayCount<rangeCount)
|
||||
{
|
||||
PRInt32 count = rangeCount-arrayCount;
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = new nsRangeStore;
|
||||
mArray.AppendElement(item);
|
||||
}
|
||||
}
|
||||
|
||||
// else if we have too many, delete them
|
||||
else if (rangeCount>arrayCount)
|
||||
{
|
||||
while ((item = (nsRangeStore*)mArray.ElementAt(rangeCount)))
|
||||
{
|
||||
delete item;
|
||||
mArray.RemoveElementAt(rangeCount);
|
||||
}
|
||||
}
|
||||
|
||||
// now store the selection ranges
|
||||
for (i=0; i<rangeCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_UNEXPECTED;
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
res = aSel->GetRangeAt(i, getter_AddRefs(range));
|
||||
item->StoreRange(range);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSelectionState::RestoreSelection(nsISelection *aSel)
|
||||
{
|
||||
if (!aSel) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
PRInt32 i, arrayCount = mArray.Count();
|
||||
nsRangeStore *item;
|
||||
|
||||
// clear out selection
|
||||
aSel->RemoveAllRanges();
|
||||
|
||||
// set the selection ranges anew
|
||||
for (i=0; i<arrayCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_UNEXPECTED;
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
item->GetRange(address_of(range));
|
||||
if (!range) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
res = aSel->AddRange(range);
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSelectionState::IsCollapsed()
|
||||
{
|
||||
if (1 != mArray.Count()) return PR_FALSE;
|
||||
nsRangeStore *item;
|
||||
item = (nsRangeStore*)mArray.ElementAt(0);
|
||||
if (!item) return PR_FALSE;
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
item->GetRange(address_of(range));
|
||||
if (!range) return PR_FALSE;
|
||||
PRBool bIsCollapsed;
|
||||
range->GetCollapsed(&bIsCollapsed);
|
||||
return bIsCollapsed;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSelectionState::IsEqual(nsSelectionState *aSelState)
|
||||
{
|
||||
if (!aSelState) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, myCount = mArray.Count(), itsCount = aSelState->mArray.Count();
|
||||
if (myCount != itsCount) return PR_FALSE;
|
||||
if (myCount < 1) return PR_FALSE;
|
||||
|
||||
nsRangeStore *myItem, *itsItem;
|
||||
|
||||
for (i=0; i<myCount; i++)
|
||||
{
|
||||
myItem = (nsRangeStore*)mArray.ElementAt(0);
|
||||
itsItem = (nsRangeStore*)(aSelState->mArray.ElementAt(0));
|
||||
if (!myItem || !itsItem) return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIDOMRange> myRange, itsRange;
|
||||
myItem->GetRange(address_of(myRange));
|
||||
itsItem->GetRange(address_of(itsRange));
|
||||
if (!myRange || !itsRange) return PR_FALSE;
|
||||
|
||||
PRInt32 compResult;
|
||||
myRange->CompareBoundaryPoints(nsIDOMRange::START_TO_START, itsRange, &compResult);
|
||||
if (compResult) return PR_FALSE;
|
||||
myRange->CompareBoundaryPoints(nsIDOMRange::END_TO_END, itsRange, &compResult);
|
||||
if (compResult) return PR_FALSE;
|
||||
}
|
||||
// if we got here, they are equal
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nsSelectionState::MakeEmpty()
|
||||
{
|
||||
// free any items in the array
|
||||
nsRangeStore *item;
|
||||
while ((item = (nsRangeStore*)mArray.ElementAt(0)))
|
||||
{
|
||||
delete item;
|
||||
mArray.RemoveElementAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSelectionState::IsEmpty()
|
||||
{
|
||||
return (mArray.Count() == 0);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* nsRangeUpdater: class for updating nsIDOMRanges in response to editor actions.
|
||||
*/
|
||||
|
||||
nsRangeUpdater::nsRangeUpdater() : mArray(), mLock(PR_FALSE) {}
|
||||
|
||||
nsRangeUpdater::~nsRangeUpdater()
|
||||
{
|
||||
// free any items in the array
|
||||
nsRangeStore *item;
|
||||
while ((item = (nsRangeStore*)mArray.ElementAt(0)))
|
||||
{
|
||||
delete item;
|
||||
mArray.RemoveElementAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
void*
|
||||
nsRangeUpdater::RegisterRange(nsIDOMRange *aRange)
|
||||
{
|
||||
nsRangeStore *item = new nsRangeStore;
|
||||
if (!item) return nsnull;
|
||||
item->StoreRange(aRange);
|
||||
mArray.AppendElement(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMRange>
|
||||
nsRangeUpdater::ReclaimRange(void *aCookie)
|
||||
{
|
||||
nsRangeStore *item = NS_STATIC_CAST(nsRangeStore*,aCookie);
|
||||
if (!item) return nsnull;
|
||||
nsCOMPtr<nsIDOMRange> outRange;
|
||||
item->GetRange(address_of(outRange));
|
||||
mArray.RemoveElement(aCookie);
|
||||
delete item;
|
||||
return outRange;
|
||||
}
|
||||
|
||||
void
|
||||
nsRangeUpdater::DropRange(void *aCookie)
|
||||
{
|
||||
nsRangeStore *item = NS_STATIC_CAST(nsRangeStore*,aCookie);
|
||||
if (!item) return;
|
||||
mArray.RemoveElement(aCookie);
|
||||
delete item;
|
||||
}
|
||||
|
||||
void
|
||||
nsRangeUpdater::RegisterRangeItem(nsRangeStore *aRangeItem)
|
||||
{
|
||||
if (!aRangeItem) return;
|
||||
mArray.AppendElement(aRangeItem);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
nsRangeUpdater::DropRangeItem(nsRangeStore *aRangeItem)
|
||||
{
|
||||
if (!aRangeItem) return;
|
||||
mArray.RemoveElement(aRangeItem);
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::RegisterSelectionState(nsSelectionState &aSelState)
|
||||
{
|
||||
PRInt32 i, theCount = aSelState.mArray.Count();
|
||||
if (theCount < 1) return NS_ERROR_FAILURE;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<theCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)aSelState.mArray.ElementAt(i);
|
||||
RegisterRangeItem(item);
|
||||
}
|
||||
|
||||
return NS_OK;;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DropSelectionState(nsSelectionState &aSelState)
|
||||
{
|
||||
PRInt32 i, theCount = aSelState.mArray.Count();
|
||||
if (theCount < 1) return NS_ERROR_FAILURE;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<theCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)aSelState.mArray.ElementAt(i);
|
||||
DropRangeItem(item);
|
||||
}
|
||||
|
||||
return NS_OK;;
|
||||
}
|
||||
|
||||
// gravity methods:
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjCreateNode(nsIDOMNode *aParent, PRInt32 aPosition)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if ((item->startNode.get() == aParent) && (item->startOffset > aPosition))
|
||||
item->startOffset++;
|
||||
if ((item->endNode.get() == aParent) && (item->endOffset > aPosition))
|
||||
item->endOffset++;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjInsertNode(nsIDOMNode *aParent, PRInt32 aPosition)
|
||||
{
|
||||
return SelAdjCreateNode(aParent, aPosition);
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjDeleteNode(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aNode) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if ((item->startNode.get() == aParent) && (item->startOffset > aOffset))
|
||||
item->startOffset--;
|
||||
if ((item->endNode.get() == aParent) && (item->endOffset > aOffset))
|
||||
item->endOffset--;
|
||||
}
|
||||
// MOOSE: also check inside of aNode, expensive. But in theory, we shouldn't
|
||||
// actually hit this case in the usage i forsee for this.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjSplitNode(nsIDOMNode *aOldRightNode, PRInt32 aOffset, nsIDOMNode *aNewLeftNode)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aOldRightNode || !aNewLeftNode) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> parent;
|
||||
PRInt32 offset;
|
||||
nsresult result = nsEditor::GetNodeLocation(aOldRightNode, address_of(parent), &offset);
|
||||
if (NS_FAILED(result)) return result;
|
||||
|
||||
// first part is same as inserting aNewLeftnode
|
||||
result = SelAdjInsertNode(parent,offset-1);
|
||||
if (NS_FAILED(result)) return result;
|
||||
|
||||
// next step is to check for range enpoints inside aOldRightNode
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (item->startNode.get() == aOldRightNode)
|
||||
{
|
||||
if (item->startOffset > aOffset)
|
||||
{
|
||||
item->startOffset -= aOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->startNode = aNewLeftNode;
|
||||
}
|
||||
}
|
||||
if (item->endNode.get() == aOldRightNode)
|
||||
{
|
||||
if (item->endOffset > aOffset)
|
||||
{
|
||||
item->endOffset -= aOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->endNode = aNewLeftNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjJoinNodes(nsIDOMNode *aLeftNode,
|
||||
nsIDOMNode *aRightNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aOffset,
|
||||
PRInt32 aOldLeftNodeLength)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aLeftNode || !aRightNode || !aParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// adjust endpoints in aParent
|
||||
if (item->startNode.get() == aParent)
|
||||
{
|
||||
if (item->startOffset > aOffset)
|
||||
{
|
||||
item->startOffset--;
|
||||
}
|
||||
else if (item->startOffset == aOffset)
|
||||
{
|
||||
// join keeps right hand node
|
||||
item->startNode = aRightNode;
|
||||
item->startOffset = aOldLeftNodeLength;
|
||||
}
|
||||
}
|
||||
if (item->endNode.get() == aParent)
|
||||
{
|
||||
if (item->endOffset > aOffset)
|
||||
{
|
||||
item->endOffset--;
|
||||
}
|
||||
else if (item->endOffset == aOffset)
|
||||
{
|
||||
// join keeps right hand node
|
||||
item->endNode = aRightNode;
|
||||
item->endOffset = aOldLeftNodeLength;
|
||||
}
|
||||
}
|
||||
// adjust endpoints in aRightNode
|
||||
if (item->startNode.get() == aRightNode)
|
||||
item->startOffset += aOldLeftNodeLength;
|
||||
if (item->endNode.get() == aRightNode)
|
||||
item->endOffset += aOldLeftNodeLength;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjInsertText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, const nsString &aString)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjDeleteText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, PRInt32 aLength)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillReplaceContainer()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidReplaceContainer(nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode)
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
|
||||
if (!aOriginalNode || !aNewNode) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (item->startNode.get() == aOriginalNode)
|
||||
item->startNode = aNewNode;
|
||||
if (item->endNode.get() == aOriginalNode)
|
||||
item->endNode = aNewNode;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillRemoveContainer()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidRemoveContainer(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset, PRUint32 aNodeOrigLen)
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
|
||||
if (!aNode || !aParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (item->startNode.get() == aNode)
|
||||
{
|
||||
item->startNode = aParent;
|
||||
item->startOffset += aOffset;
|
||||
}
|
||||
if (item->endNode.get() == aNode)
|
||||
{
|
||||
item->endNode = aParent;
|
||||
item->endOffset += aOffset;
|
||||
}
|
||||
if ((item->startNode.get() == aParent) && (item->startOffset > aOffset))
|
||||
item->startOffset += (PRInt32)aNodeOrigLen-1;
|
||||
if ((item->endNode.get() == aParent) && (item->endOffset > aOffset))
|
||||
item->endOffset += (PRInt32)aNodeOrigLen-1;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillInsertContainer()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidInsertContainer()
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillMoveNode()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidMoveNode(nsIDOMNode *aOldParent, PRInt32 aOldOffset, nsIDOMNode *aNewParent, PRInt32 aNewOffset)
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
|
||||
if (!aOldParent || !aNewParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// like a delete in aOldParent
|
||||
if ((item->startNode.get() == aOldParent) && (item->startOffset > aOldOffset))
|
||||
item->startOffset--;
|
||||
if ((item->endNode.get() == aOldParent) && (item->endOffset > aOldOffset))
|
||||
item->endOffset--;
|
||||
|
||||
// and like an insert in aNewParent
|
||||
if ((item->startNode.get() == aNewParent) && (item->startOffset > aNewOffset))
|
||||
item->startOffset++;
|
||||
if ((item->endNode.get() == aNewParent) && (item->endOffset > aNewOffset))
|
||||
item->endOffset++;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* helper class for nsSelectionState. nsRangeStore stores range endpoints.
|
||||
*/
|
||||
|
||||
// DEBUG: PRInt32 nsRangeStore::n = 0;
|
||||
|
||||
nsRangeStore::nsRangeStore()
|
||||
{
|
||||
// DEBUG: n++; printf("range store alloc count=%d\n", n);
|
||||
}
|
||||
nsRangeStore::~nsRangeStore()
|
||||
{
|
||||
// DEBUG: n--; printf("range store alloc count=%d\n", n);
|
||||
}
|
||||
|
||||
nsresult nsRangeStore::StoreRange(nsIDOMRange *aRange)
|
||||
{
|
||||
if (!aRange) return NS_ERROR_NULL_POINTER;
|
||||
aRange->GetStartContainer(getter_AddRefs(startNode));
|
||||
aRange->GetEndContainer(getter_AddRefs(endNode));
|
||||
aRange->GetStartOffset(&startOffset);
|
||||
aRange->GetEndOffset(&endOffset);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsRangeStore::GetRange(nsCOMPtr<nsIDOMRange> *outRange)
|
||||
{
|
||||
if (!outRange) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = nsComponentManager::CreateInstance(kCRangeCID,
|
||||
nsnull,
|
||||
NS_GET_IID(nsIDOMRange),
|
||||
getter_AddRefs(*outRange));
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
res = (*outRange)->SetStart(startNode, startOffset);
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
res = (*outRange)->SetEnd(endNode, endOffset);
|
||||
return res;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidReplaceContainer()
|
||||
*/
|
||||
|
||||
class nsAutoReplaceContainerSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
nsIDOMNode *mOriginalNode;
|
||||
nsIDOMNode *mNewNode;
|
||||
|
||||
public:
|
||||
nsAutoReplaceContainerSelNotify(nsRangeUpdater &aRangeUpdater, nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode) :
|
||||
mRU(aRangeUpdater)
|
||||
,mOriginalNode(aOriginalNode)
|
||||
,mNewNode(aNewNode)
|
||||
{
|
||||
mRU.WillReplaceContainer();
|
||||
}
|
||||
|
||||
~nsAutoReplaceContainerSelNotify()
|
||||
{
|
||||
mRU.DidReplaceContainer(mOriginalNode, mNewNode);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidRemoveContainer()
|
||||
*/
|
||||
|
||||
class nsAutoRemoveContainerSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
nsIDOMNode *mNode;
|
||||
nsIDOMNode *mParent;
|
||||
PRInt32 mOffset;
|
||||
PRUint32 mNodeOrigLen;
|
||||
|
||||
public:
|
||||
nsAutoRemoveContainerSelNotify(nsRangeUpdater &aRangeUpdater,
|
||||
nsIDOMNode *aNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aOffset,
|
||||
PRUint32 aNodeOrigLen) :
|
||||
mRU(aRangeUpdater)
|
||||
,mNode(aNode)
|
||||
,mParent(aParent)
|
||||
,mOffset(aOffset)
|
||||
,mNodeOrigLen(aNodeOrigLen)
|
||||
{
|
||||
mRU.WillRemoveContainer();
|
||||
}
|
||||
|
||||
~nsAutoRemoveContainerSelNotify()
|
||||
{
|
||||
mRU.DidRemoveContainer(mNode, mParent, mOffset, mNodeOrigLen);
|
||||
}
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidInsertContainer()
|
||||
*/
|
||||
|
||||
class nsAutoInsertContainerSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
|
||||
public:
|
||||
nsAutoInsertContainerSelNotify(nsRangeUpdater &aRangeUpdater) :
|
||||
mRU(aRangeUpdater)
|
||||
{
|
||||
mRU.WillInsertContainer();
|
||||
}
|
||||
|
||||
~nsAutoInsertContainerSelNotify()
|
||||
{
|
||||
mRU.DidInsertContainer();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidMoveNode()
|
||||
*/
|
||||
|
||||
class nsAutoMoveNodeSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
nsIDOMNode *mOldParent;
|
||||
nsIDOMNode *mNewParent;
|
||||
PRInt32 mOldOffset;
|
||||
PRInt32 mNewOffset;
|
||||
|
||||
public:
|
||||
nsAutoMoveNodeSelNotify(nsRangeUpdater &aRangeUpdater,
|
||||
nsIDOMNode *aOldParent,
|
||||
PRInt32 aOldOffset,
|
||||
nsIDOMNode *aNewParent,
|
||||
PRInt32 aNewOffset) :
|
||||
mRU(aRangeUpdater)
|
||||
,mOldParent(aOldParent)
|
||||
,mNewParent(aNewParent)
|
||||
,mOldOffset(aOldOffset)
|
||||
,mNewOffset(aNewOffset)
|
||||
{
|
||||
mRU.WillMoveNode();
|
||||
}
|
||||
|
||||
~nsAutoMoveNodeSelNotify()
|
||||
{
|
||||
mRU.DidMoveNode(mOldParent, mOldOffset, mNewParent, mNewOffset);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// nsEditor: base editor class implementation
|
||||
@ -2606,7 +1875,7 @@ nsEditor::ForceCompositionEnd()
|
||||
#endif
|
||||
|
||||
#ifdef XP_UNIX
|
||||
if(mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
||||
if(mFlags & nsIPlaintextEditor::eEditorPasswordMask)
|
||||
return NS_OK;
|
||||
#endif
|
||||
|
||||
@ -5059,7 +4328,6 @@ nsEditor::IsNextCharWhitespace(nsIDOMNode *aParentNode,
|
||||
textNode->GetLength(&strLength);
|
||||
if (strLength)
|
||||
{
|
||||
// you could use nsITextContent::IsOnlyWhitespace here
|
||||
textNode->SubstringData(0,1,tempString);
|
||||
*outIsSpace = nsCRT::IsAsciiSpace(tempString.First());
|
||||
*outIsNBSP = (tempString.First() == nbsp);
|
||||
@ -5391,7 +4659,7 @@ nsresult nsEditor::EndUpdateViewBatch()
|
||||
|
||||
PRBool forceReflow = PR_TRUE;
|
||||
|
||||
if (flags & nsIHTMLEditor::eEditorDisableForcedReflowsMask)
|
||||
if (flags & nsIPlaintextEditor::eEditorDisableForcedReflowsMask)
|
||||
forceReflow = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
@ -5401,7 +4669,7 @@ nsresult nsEditor::EndUpdateViewBatch()
|
||||
|
||||
PRUint32 updateFlag = NS_VMREFRESH_IMMEDIATE;
|
||||
|
||||
if (flags & nsIHTMLEditor::eEditorDisableForcedUpdatesMask)
|
||||
if (flags & nsIPlaintextEditor::eEditorDisableForcedUpdatesMask)
|
||||
updateFlag = NS_VMREFRESH_NO_SYNC;
|
||||
|
||||
#ifdef HACK_FORCE_REDRAW
|
||||
@ -5482,9 +4750,129 @@ nsEditor::DeleteSelectionImpl(nsIEditor::EDirection aAction)
|
||||
return res;
|
||||
}
|
||||
|
||||
// XXX: error handling in this routine needs to be cleaned up!
|
||||
NS_IMETHODIMP
|
||||
nsEditor::DeleteSelectionAndCreateNode(const nsString& aTag,
|
||||
nsIDOMNode ** aNewNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> parentSelectedNode;
|
||||
PRInt32 offsetOfNewNode;
|
||||
nsresult result = DeleteSelectionAndPrepareToCreateNode(parentSelectedNode,
|
||||
offsetOfNewNode);
|
||||
if (!NS_SUCCEEDED(result))
|
||||
return result;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
result = CreateNode(aTag, parentSelectedNode, offsetOfNewNode,
|
||||
getter_AddRefs(newNode));
|
||||
// XXX: ERROR_HANDLING check result, and make sure aNewNode is set correctly in success/failure cases
|
||||
*aNewNode = newNode;
|
||||
NS_IF_ADDREF(*aNewNode);
|
||||
|
||||
// we want the selection to be just after the new node
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
result = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(result)) return result;
|
||||
if (!selection) return NS_ERROR_NULL_POINTER;
|
||||
result = selection->Collapse(parentSelectedNode, offsetOfNewNode+1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Non-interface, protected methods */
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNode> &parentSelectedNode, PRInt32& offsetOfNewNode)
|
||||
{
|
||||
nsresult result=NS_ERROR_NOT_INITIALIZED;
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
result = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(result)) return result;
|
||||
if (!selection) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
PRBool collapsed;
|
||||
result = selection->GetIsCollapsed(&collapsed);
|
||||
if (NS_SUCCEEDED(result) && !collapsed)
|
||||
{
|
||||
result = DeleteSelection(nsIEditor::eNone);
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
// get the new selection
|
||||
result = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
#ifdef NS_DEBUG
|
||||
nsCOMPtr<nsIDOMNode>testSelectedNode;
|
||||
nsresult debugResult = selection->GetAnchorNode(getter_AddRefs(testSelectedNode));
|
||||
// no selection is ok.
|
||||
// if there is a selection, it must be collapsed
|
||||
if (testSelectedNode)
|
||||
{
|
||||
PRBool testCollapsed;
|
||||
debugResult = selection->GetIsCollapsed(&testCollapsed);
|
||||
NS_ASSERTION((NS_SUCCEEDED(result)), "couldn't get a selection after deletion");
|
||||
NS_ASSERTION(testCollapsed, "selection not reset after deletion");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// split the selected node
|
||||
PRInt32 offsetOfSelectedNode;
|
||||
result = selection->GetAnchorNode(getter_AddRefs(parentSelectedNode));
|
||||
if (NS_SUCCEEDED(result) && NS_SUCCEEDED(selection->GetAnchorOffset(&offsetOfSelectedNode)) && parentSelectedNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> selectedNode;
|
||||
PRUint32 selectedNodeContentCount=0;
|
||||
nsCOMPtr<nsIDOMCharacterData>selectedParentNodeAsText;
|
||||
selectedParentNodeAsText = do_QueryInterface(parentSelectedNode);
|
||||
|
||||
offsetOfNewNode = offsetOfSelectedNode;
|
||||
|
||||
/* if the selection is a text node, split the text node if necesary
|
||||
and compute where to put the new node
|
||||
*/
|
||||
if (selectedParentNodeAsText)
|
||||
{
|
||||
PRInt32 indexOfTextNodeInParent;
|
||||
selectedNode = do_QueryInterface(parentSelectedNode);
|
||||
selectedNode->GetParentNode(getter_AddRefs(parentSelectedNode));
|
||||
selectedParentNodeAsText->GetLength(&selectedNodeContentCount);
|
||||
GetChildOffset(selectedNode, parentSelectedNode, indexOfTextNodeInParent);
|
||||
|
||||
if ((offsetOfSelectedNode!=0) && (((PRUint32)offsetOfSelectedNode)!=selectedNodeContentCount))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> newSiblingNode;
|
||||
result = SplitNode(selectedNode, offsetOfSelectedNode, getter_AddRefs(newSiblingNode));
|
||||
// now get the node's offset in it's parent, and insert the new tag there
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
result = GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // determine where to insert the new node
|
||||
if (0==offsetOfSelectedNode) {
|
||||
offsetOfNewNode = indexOfTextNodeInParent; // insert new node as previous sibling to selection parent
|
||||
}
|
||||
else { // insert new node as last child
|
||||
GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
|
||||
offsetOfNewNode++; // offsets are 0-based, and we need the index of the new node
|
||||
}
|
||||
}
|
||||
}
|
||||
// Here's where the new node was inserted
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else {
|
||||
printf("InsertLineBreak into an empty document is not yet supported\n");
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::DoAfterDoTransaction(nsITransaction *aTxn)
|
||||
{
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "nsIDTD.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsSelectionState.h"
|
||||
|
||||
class nsIEditActionListener;
|
||||
class nsIDocumentStateListener;
|
||||
@ -72,92 +73,6 @@ class nsIFile;
|
||||
class nsISelectionController;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* class for recording selection info. stores selection as collection of
|
||||
* { {startnode, startoffset} , {endnode, endoffset} } tuples. Cant store
|
||||
* ranges since dom gravity will possibly change the ranges.
|
||||
*/
|
||||
|
||||
// first a helper struct for saving/setting ranges
|
||||
struct nsRangeStore
|
||||
{
|
||||
nsRangeStore();
|
||||
~nsRangeStore();
|
||||
nsresult StoreRange(nsIDOMRange *aRange);
|
||||
nsresult GetRange(nsCOMPtr<nsIDOMRange> *outRange);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> startNode;
|
||||
PRInt32 startOffset;
|
||||
nsCOMPtr<nsIDOMNode> endNode;
|
||||
PRInt32 endOffset;
|
||||
// DEBUG: static PRInt32 n;
|
||||
};
|
||||
|
||||
class nsSelectionState
|
||||
{
|
||||
public:
|
||||
|
||||
nsSelectionState();
|
||||
~nsSelectionState();
|
||||
|
||||
nsresult SaveSelection(nsISelection *aSel);
|
||||
nsresult RestoreSelection(nsISelection *aSel);
|
||||
PRBool IsCollapsed();
|
||||
PRBool IsEqual(nsSelectionState *aSelState);
|
||||
void MakeEmpty();
|
||||
PRBool IsEmpty();
|
||||
protected:
|
||||
nsVoidArray mArray;
|
||||
|
||||
friend class nsRangeUpdater;
|
||||
};
|
||||
|
||||
class nsRangeUpdater
|
||||
{
|
||||
public:
|
||||
|
||||
nsRangeUpdater();
|
||||
~nsRangeUpdater();
|
||||
|
||||
void* RegisterRange(nsIDOMRange *aRange);
|
||||
nsCOMPtr<nsIDOMRange> ReclaimRange(void *aCookie);
|
||||
void DropRange(void *aCookie);
|
||||
void RegisterRangeItem(nsRangeStore *aRangeItem);
|
||||
void DropRangeItem(nsRangeStore *aRangeItem);
|
||||
nsresult RegisterSelectionState(nsSelectionState &aSelState);
|
||||
nsresult DropSelectionState(nsSelectionState &aSelState);
|
||||
|
||||
// editor selection gravity routines. Note that we can't always depend on
|
||||
// DOM Range gravity to do what we want to the "real" selection. For instance,
|
||||
// if you move a node, that corresponds to deleting it and reinserting it.
|
||||
// DOM Range gravity will promote the selection out of the node on deletion,
|
||||
// which is not what you want if you know you are reinserting it.
|
||||
nsresult SelAdjCreateNode(nsIDOMNode *aParent, PRInt32 aPosition);
|
||||
nsresult SelAdjInsertNode(nsIDOMNode *aParent, PRInt32 aPosition);
|
||||
nsresult SelAdjDeleteNode(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset);
|
||||
nsresult SelAdjSplitNode(nsIDOMNode *aOldRightNode, PRInt32 aOffset, nsIDOMNode *aNewLeftNode);
|
||||
nsresult SelAdjJoinNodes(nsIDOMNode *aLeftNode,
|
||||
nsIDOMNode *aRightNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aOffset,
|
||||
PRInt32 aOldLeftNodeLength);
|
||||
nsresult SelAdjInsertText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, const nsString &aString);
|
||||
nsresult SelAdjDeleteText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, PRInt32 aLength);
|
||||
// the following gravity routines need will/did sandwiches, because the other gravity
|
||||
// routines will be called inside of these sandwiches, but should be ignored.
|
||||
nsresult WillReplaceContainer();
|
||||
nsresult DidReplaceContainer(nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode);
|
||||
nsresult WillRemoveContainer();
|
||||
nsresult DidRemoveContainer(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset, PRUint32 aNodeOrigLen);
|
||||
nsresult WillInsertContainer();
|
||||
nsresult DidInsertContainer();
|
||||
nsresult WillMoveNode();
|
||||
nsresult DidMoveNode(nsIDOMNode *aOldParent, PRInt32 aOldOffset, nsIDOMNode *aNewParent, PRInt32 aNewOffset);
|
||||
protected:
|
||||
nsVoidArray mArray;
|
||||
PRBool mLock;
|
||||
};
|
||||
|
||||
/** implementation of an editor object. it will be the controller/focal point
|
||||
* for the main editor services. i.e. the GUIManager, publishing, transaction
|
||||
* manager, event interfaces. the idea for the event interfaces is to have them
|
||||
@ -181,18 +96,17 @@ public:
|
||||
kOpNone = 0,
|
||||
kOpUndo,
|
||||
kOpRedo,
|
||||
kOpSetTextProperty,
|
||||
kOpRemoveTextProperty,
|
||||
kOpInsertNode,
|
||||
kOpCreateNode,
|
||||
kOpDeleteNode,
|
||||
kOpSplitNode,
|
||||
kOpJoinNode,
|
||||
kOpDeleteText,
|
||||
kOpInsertText,
|
||||
kOpInsertIMEText,
|
||||
kOpDeleteSelection,
|
||||
kOpHTMLPaste
|
||||
// text commands
|
||||
kOpInsertBreak = 1000,
|
||||
kOpInsertText = 1001,
|
||||
kOpInsertIMEText = 1002,
|
||||
kOpDeleteText = 1003
|
||||
};
|
||||
|
||||
static const char* kMOZEditorBogusNodeAttr;
|
||||
@ -341,6 +255,8 @@ public:
|
||||
nsIDOMCharacterData *aTextNode,
|
||||
PRInt32 aOffset);
|
||||
NS_IMETHOD DeleteSelectionImpl(EDirection aAction);
|
||||
NS_IMETHOD DeleteSelectionAndCreateNode(const nsString& aTag,
|
||||
nsIDOMNode ** aNewNode);
|
||||
|
||||
/* helper routines for node/parent manipulations */
|
||||
nsresult ReplaceContainer(nsIDOMNode *inNode,
|
||||
@ -454,6 +370,8 @@ protected:
|
||||
nsIDOMNode *aRightNode,
|
||||
JoinElementTxn **aTxn);
|
||||
|
||||
NS_IMETHOD DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNode> &parentSelectedNode,
|
||||
PRInt32& offsetOfNewNode);
|
||||
|
||||
// called each time we modify the document. Increments the mod
|
||||
// count of the doc.
|
||||
@ -775,7 +693,7 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
PRUint32 mFlags; // behavior flags. See nsIHTMLEditor.h for the flags we use.
|
||||
PRUint32 mFlags; // behavior flags. See nsPlaintextEditor.h for the flags we use.
|
||||
|
||||
nsWeakPtr mPresShellWeak; // weak reference to the nsIPresShell
|
||||
nsWeakPtr mSelConWeak; // weak reference to the nsISelectionController
|
||||
|
@ -21,7 +21,7 @@
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
*/
|
||||
#include "nsEditorEventListeners.h"
|
||||
#include "nsIPlaintextEditor.h"
|
||||
#include "nsIHTMLEditor.h"
|
||||
#include "nsEditor.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsString.h"
|
||||
@ -178,8 +178,8 @@ nsTextEditorKeyListener::KeyPress(nsIDOMEvent* aKeyEvent)
|
||||
// if we are readonly or disabled, then do nothing.
|
||||
if (NS_SUCCEEDED(mEditor->GetFlags(&flags)))
|
||||
{
|
||||
if (flags & nsIHTMLEditor::eEditorReadonlyMask ||
|
||||
flags & nsIHTMLEditor::eEditorDisabledMask)
|
||||
if (flags & nsIPlaintextEditor::eEditorReadonlyMask ||
|
||||
flags & nsIPlaintextEditor::eEditorDisabledMask)
|
||||
return NS_OK;
|
||||
}
|
||||
else
|
||||
@ -246,7 +246,7 @@ nsTextEditorKeyListener::KeyPress(nsIDOMEvent* aKeyEvent)
|
||||
break;
|
||||
|
||||
case nsIDOMKeyEvent::DOM_VK_TAB:
|
||||
if ((flags & nsIHTMLEditor::eEditorSingleLineMask))
|
||||
if ((flags & nsIPlaintextEditor::eEditorSingleLineMask))
|
||||
return NS_OK; // let it be used for focus switching
|
||||
|
||||
// else we insert the tab straight through
|
||||
@ -257,9 +257,8 @@ nsTextEditorKeyListener::KeyPress(nsIDOMEvent* aKeyEvent)
|
||||
|
||||
case nsIDOMKeyEvent::DOM_VK_RETURN:
|
||||
case nsIDOMKeyEvent::DOM_VK_ENTER:
|
||||
if (!(flags & nsIHTMLEditor::eEditorSingleLineMask))
|
||||
if (!(flags & nsIPlaintextEditor::eEditorSingleLineMask))
|
||||
{
|
||||
//htmlEditor->InsertBreak();
|
||||
textEditor->HandleKeyPress(keyEvent);
|
||||
ScrollSelectionIntoView(mEditor);
|
||||
aKeyEvent->PreventDefault(); // consumed
|
||||
@ -642,8 +641,8 @@ nsTextEditorDragListener::DragOver(nsIDOMEvent* aDragEvent)
|
||||
if ( dragSession ) {
|
||||
PRUint32 flags;
|
||||
if (NS_SUCCEEDED(mEditor->GetFlags(&flags))) {
|
||||
if ((flags & nsIHTMLEditor::eEditorDisabledMask) ||
|
||||
(flags & nsIHTMLEditor::eEditorReadonlyMask)) {
|
||||
if ((flags & nsIPlaintextEditor::eEditorDisabledMask) ||
|
||||
(flags & nsIPlaintextEditor::eEditorReadonlyMask)) {
|
||||
dragSession->SetCanDrop(PR_FALSE);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1041,7 +1040,7 @@ nsTextEditorFocusListener::Focus(nsIDOMEvent* aEvent)
|
||||
PRUint32 flags;
|
||||
aEvent->PreventBubble();
|
||||
mEditor->GetFlags(&flags);
|
||||
if (! (flags & nsIHTMLEditor::eEditorDisabledMask))
|
||||
if (! (flags & nsIPlaintextEditor::eEditorDisabledMask))
|
||||
{ // only enable caret and selection if the editor is not disabled
|
||||
nsCOMPtr<nsIEditor>editor = do_QueryInterface(mEditor);
|
||||
if (editor)
|
||||
@ -1050,7 +1049,7 @@ nsTextEditorFocusListener::Focus(nsIDOMEvent* aEvent)
|
||||
editor->GetSelectionController(getter_AddRefs(selCon));
|
||||
if (selCon)
|
||||
{
|
||||
if (! (flags & nsIHTMLEditor::eEditorReadonlyMask))
|
||||
if (! (flags & nsIPlaintextEditor::eEditorReadonlyMask))
|
||||
{ // only enable caret if the editor is not readonly
|
||||
PRInt32 pixelWidth;
|
||||
nsresult result;
|
||||
@ -1059,7 +1058,7 @@ nsTextEditorFocusListener::Focus(nsIDOMEvent* aEvent)
|
||||
|
||||
if (NS_SUCCEEDED(result) && look)
|
||||
{
|
||||
if(flags & nsIHTMLEditor::eEditorSingleLineMask)
|
||||
if(flags & nsIPlaintextEditor::eEditorSingleLineMask)
|
||||
look->GetMetric(nsILookAndFeel::eMetric_SingleLineCaretWidth, pixelWidth);
|
||||
else
|
||||
look->GetMetric(nsILookAndFeel::eMetric_MultiLineCaretWidth, pixelWidth);
|
||||
@ -1109,11 +1108,11 @@ nsTextEditorFocusListener::Blur(nsIDOMEvent* aEvent)
|
||||
if (selCon)
|
||||
{
|
||||
selCon->SetCaretEnabled(PR_FALSE);
|
||||
if((flags & nsIHTMLEditor::eEditorWidgetMask) ||
|
||||
(flags & nsIHTMLEditor::eEditorPasswordMask) ||
|
||||
(flags & nsIHTMLEditor::eEditorReadonlyMask) ||
|
||||
(flags & nsIHTMLEditor::eEditorDisabledMask) ||
|
||||
(flags & nsIHTMLEditor::eEditorFilterInputMask))
|
||||
if((flags & nsIPlaintextEditor::eEditorWidgetMask) ||
|
||||
(flags & nsIPlaintextEditor::eEditorPasswordMask) ||
|
||||
(flags & nsIPlaintextEditor::eEditorReadonlyMask) ||
|
||||
(flags & nsIPlaintextEditor::eEditorDisabledMask) ||
|
||||
(flags & nsIPlaintextEditor::eEditorFilterInputMask))
|
||||
{
|
||||
selCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);//hide but do NOT turn off
|
||||
}
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include "nsIDOMFocusListener.h"
|
||||
|
||||
#include "nsIEditor.h"
|
||||
#include "nsIHTMLEditor.h"
|
||||
#include "nsIPlaintextEditor.h"
|
||||
|
||||
/** The nsTextEditorKeyListener public nsIDOMKeyListener
|
||||
* This class will delegate events to its editor according to the translation
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "nsEditor.h" // for gInstanceCount
|
||||
#include "nsEditorController.h" //CID
|
||||
#include "nsEditorService.h"
|
||||
#include "nsPlaintextEditor.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Define the contructor function for the objects
|
||||
@ -38,6 +39,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorShell)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorController)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsComposerController)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorService)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsPlaintextEditor)
|
||||
|
||||
#ifdef ENABLE_EDITOR_API_LOG
|
||||
#include "nsHTMLEditorLog.h"
|
||||
@ -52,6 +54,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLEditor)
|
||||
// class name.
|
||||
//
|
||||
static nsModuleComponentInfo components[] = {
|
||||
{ "Text Editor", NS_TEXTEDITOR_CID,
|
||||
"@mozilla.org/editor/texteditor;1", nsPlaintextEditorConstructor, },
|
||||
#ifdef ENABLE_EDITOR_API_LOG
|
||||
{ "HTML Editor", NS_HTMLEDITOR_CID,
|
||||
"@mozilla.org/editor/htmleditor;1", nsHTMLEditorLogConstructor, },
|
||||
|
@ -910,7 +910,7 @@ nsEditorShell::InstantiateEditor(nsIDOMDocument *aDoc, nsIPresShell *aPresShell)
|
||||
{
|
||||
if (mEditorTypeString.EqualsWithConversion("text"))
|
||||
{
|
||||
err = editor->Init(aDoc, aPresShell, nsnull, selCon, nsIHTMLEditor::eEditorPlaintextMask | nsIHTMLEditor::eEditorEnableWrapHackMask);
|
||||
err = editor->Init(aDoc, aPresShell, nsnull, selCon, nsIPlaintextEditor::eEditorPlaintextMask | nsIPlaintextEditor::eEditorEnableWrapHackMask);
|
||||
mEditorType = ePlainTextEditorType;
|
||||
}
|
||||
else if (mEditorTypeString.EqualsWithConversion("html") || mEditorTypeString.IsEmpty()) // empty string default to HTML editor
|
||||
@ -920,7 +920,7 @@ nsEditorShell::InstantiateEditor(nsIDOMDocument *aDoc, nsIPresShell *aPresShell)
|
||||
}
|
||||
else if (mEditorTypeString.EqualsWithConversion("htmlmail")) // HTML editor with special mail rules
|
||||
{
|
||||
err = editor->Init(aDoc, aPresShell, nsnull, selCon, nsIHTMLEditor::eEditorMailMask);
|
||||
err = editor->Init(aDoc, aPresShell, nsnull, selCon, nsIPlaintextEditor::eEditorMailMask);
|
||||
mEditorType = eHTMLTextEditorType;
|
||||
}
|
||||
else
|
||||
@ -3423,7 +3423,7 @@ nsEditorShell::GetDocumentEditable(PRBool *aDocumentEditable)
|
||||
PRUint32 editorFlags;
|
||||
editor->GetFlags(&editorFlags);
|
||||
|
||||
if (editorFlags & nsIHTMLEditor::eEditorReadonlyMask)
|
||||
if (editorFlags & nsIPlaintextEditor::eEditorReadonlyMask)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> doc;
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "nsIAtom.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsEditor.h"
|
||||
#include "nsPlaintextEditor.h"
|
||||
#include "nsIContentIterator.h"
|
||||
|
||||
/***************************************************************************
|
||||
@ -48,6 +49,22 @@ class nsAutoPlaceHolderBatch
|
||||
~nsAutoPlaceHolderBatch() { if (mEd) mEd->EndPlaceHolderTransaction(); }
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
* stack based helper class for detecting end of editor initialization, in
|
||||
* order to triger "end of init" initialization of the edit rules.
|
||||
*/
|
||||
class nsAutoEditInitRulesTrigger
|
||||
{
|
||||
private:
|
||||
nsPlaintextEditor *mEd;
|
||||
nsresult &mRes;
|
||||
public:
|
||||
nsAutoEditInitRulesTrigger( nsPlaintextEditor *aEd, nsresult &aRes) : mEd(aEd), mRes(aRes)
|
||||
{ if (mEd) mEd->BeginEditorInit(); }
|
||||
~nsAutoEditInitRulesTrigger() { if (mEd) mRes = mEd->EndEditorInit(); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* stack based helper class for batching a collection of txns.
|
||||
|
1619
editor/base/nsHTMLDataTransfer.cpp
Normal file
1619
editor/base/nsHTMLDataTransfer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -34,6 +34,7 @@ class nsISupportsArray;
|
||||
class nsVoidArray;
|
||||
class nsIDOMElement;
|
||||
class nsIEditor;
|
||||
class nsHTMLEditor;
|
||||
|
||||
class nsHTMLEditRules : public nsIHTMLEditRules, public nsTextEditRules, public nsIEditActionListener
|
||||
{
|
||||
@ -46,7 +47,7 @@ public:
|
||||
|
||||
|
||||
// nsIEditRules methods
|
||||
NS_IMETHOD Init(nsHTMLEditor *aEditor, PRUint32 aFlags);
|
||||
NS_IMETHOD Init(nsPlaintextEditor *aEditor, PRUint32 aFlags);
|
||||
NS_IMETHOD BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection);
|
||||
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection);
|
||||
NS_IMETHOD WillDoAction(nsISelection *aSelection, nsRulesInfo *aInfo, PRBool *aCancel, PRBool *aHandled);
|
||||
@ -98,10 +99,10 @@ protected:
|
||||
nsString *outString,
|
||||
PRInt32 aMaxLength);
|
||||
nsresult WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult DidInsertBreak(nsISelection *aSelection, nsresult aResult);
|
||||
nsresult WillDeleteSelection(nsISelection *aSelection, nsIEditor::EDirection aAction,
|
||||
PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult DeleteNonTableElements(nsIDOMNode *aNode);
|
||||
|
||||
nsresult WillMakeList(nsISelection *aSelection, const nsString *aListType, PRBool aEntireList, PRBool *aCancel, PRBool *aHandled, const nsString *aItemType=nsnull);
|
||||
nsresult WillRemoveList(nsISelection *aSelection, PRBool aOrderd, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillIndent(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled);
|
||||
@ -110,17 +111,13 @@ protected:
|
||||
nsresult WillMakeDefListItem(nsISelection *aSelection, const nsString *aBlockType, PRBool aEntireList, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillMakeBasicBlock(nsISelection *aSelection, const nsString *aBlockType, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult DidMakeBasicBlock(nsISelection *aSelection, nsRulesInfo *aInfo, nsresult aResult);
|
||||
|
||||
nsresult AlignInnerBlocks(nsIDOMNode *aNode, const nsString *alignType);
|
||||
nsresult AlignBlockContents(nsIDOMNode *aNode, const nsString *alignType);
|
||||
nsresult GetInnerContent(nsIDOMNode *aNode, nsISupportsArray *outArrayOfNodes, PRBool aList = PR_TRUE, PRBool aTble = PR_TRUE);
|
||||
|
||||
nsresult InsertTab(nsISelection *aSelection, nsString *outString);
|
||||
|
||||
nsresult ReturnInHeader(nsISelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset);
|
||||
nsresult ReturnInParagraph(nsISelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult ReturnInListItem(nsISelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset);
|
||||
|
||||
nsresult AfterEditInner(PRInt32 action, nsIEditor::EDirection aDirection);
|
||||
nsresult ConvertListType(nsIDOMNode *aList, nsCOMPtr<nsIDOMNode> *outList, const nsString& aListType, const nsString& aItemType);
|
||||
nsresult CreateStyleForInsertText(nsISelection *aSelection, nsIDOMDocument *aDoc);
|
||||
@ -132,7 +129,6 @@ protected:
|
||||
PRBool IsLastNode(nsIDOMNode *aNode);
|
||||
PRBool AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock);
|
||||
PRBool AtEndOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock);
|
||||
|
||||
nsresult GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt32 aOffset,
|
||||
PRInt32 actionID, nsCOMPtr<nsIDOMNode> *outNode, PRInt32 *outOffset);
|
||||
nsresult GetPromotedRanges(nsISelection *inSelection,
|
||||
@ -154,20 +150,16 @@ protected:
|
||||
nsCOMPtr<nsIDOMNode> GetHighestInlineParent(nsIDOMNode* aNode);
|
||||
nsresult MakeTransitionList(nsISupportsArray *inArrayOfNodes,
|
||||
nsVoidArray *inTransitionArray);
|
||||
|
||||
nsresult ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString *aBlockTag);
|
||||
nsresult MakeBlockquote(nsISupportsArray *arrayOfNodes);
|
||||
nsresult SplitAsNeeded(const nsString *aTag, nsCOMPtr<nsIDOMNode> *inOutParent, PRInt32 *inOutOffset);
|
||||
nsresult AddTerminatingBR(nsIDOMNode *aBlock);
|
||||
|
||||
nsresult JoinNodesSmart( nsIDOMNode *aNodeLeft,
|
||||
nsIDOMNode *aNodeRight,
|
||||
nsCOMPtr<nsIDOMNode> *aOutMergeParent,
|
||||
PRInt32 *aOutMergeOffset);
|
||||
|
||||
nsresult GetTopEnclosingMailCite(nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutCiteNode);
|
||||
nsresult GetTopEnclosingMailCite(nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutCiteNode, PRBool aPlaintext);
|
||||
nsresult PopListItem(nsIDOMNode *aListItem, PRBool *aOutOfList);
|
||||
|
||||
nsresult AdjustSpecialBreaks(PRBool aSafeToAskFrames = PR_FALSE);
|
||||
nsresult AdjustWhitespace(nsISelection *aSelection);
|
||||
nsresult AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection aAction);
|
||||
@ -180,14 +172,13 @@ protected:
|
||||
nsresult SelectionEndpointInNode(nsIDOMNode *aNode, PRBool *aResult);
|
||||
nsresult DoTextNodeWhitespace(nsIDOMCharacterData *aTextNode, PRInt32 aStart, PRInt32 aEnd);
|
||||
nsresult UpdateDocChangeRange(nsIDOMRange *aRange);
|
||||
|
||||
nsresult ConvertWhitespace(const nsString & inString, nsString & outString);
|
||||
nsresult ConfirmSelectionInBody();
|
||||
|
||||
nsresult InsertMozBRIfNeeded(nsIDOMNode *aNode);
|
||||
|
||||
// data members
|
||||
protected:
|
||||
nsHTMLEditor *mHTMLEditor;
|
||||
nsCOMPtr<nsIDOMRange> mDocChangeRange;
|
||||
PRBool mListenerEnabled;
|
||||
PRBool mReturnInEmptyLIKillsList;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "nsEditor.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsIDOMNodeList.h"
|
||||
#include "nsIDOMHTMLAnchorElement.h"
|
||||
|
||||
/********************************************************
|
||||
* helper methods from nsTextEditRules
|
||||
@ -487,6 +488,34 @@ nsHTMLEditUtils::IsImage(nsIDOMNode *node)
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHTMLEditUtils::IsLink(nsIDOMNode *aNode)
|
||||
{
|
||||
if (!aNode) return PR_FALSE;
|
||||
nsCOMPtr<nsIDOMHTMLAnchorElement> anchor = do_QueryInterface(aNode);
|
||||
if (anchor)
|
||||
{
|
||||
nsAutoString tmpText;
|
||||
if (NS_SUCCEEDED(anchor->GetHref(tmpText)) && tmpText.GetUnicode() && tmpText.Length() != 0)
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHTMLEditUtils::IsNamedAnchor(nsIDOMNode *aNode)
|
||||
{
|
||||
if (!aNode) return PR_FALSE;
|
||||
nsCOMPtr<nsIDOMHTMLAnchorElement> anchor = do_QueryInterface(aNode);
|
||||
if (anchor)
|
||||
{
|
||||
nsAutoString tmpText;
|
||||
if (NS_SUCCEEDED(anchor->GetName(tmpText)) && tmpText.GetUnicode() && tmpText.Length() != 0)
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// IsDiv: true if node an html div node
|
||||
|
@ -58,6 +58,8 @@ public:
|
||||
static PRBool IsAddress(nsIDOMNode *aNode);
|
||||
static PRBool IsAnchor(nsIDOMNode *aNode);
|
||||
static PRBool IsImage(nsIDOMNode *aNode);
|
||||
static PRBool IsLink(nsIDOMNode *aNode);
|
||||
static PRBool IsNamedAnchor(nsIDOMNode *aNode);
|
||||
static PRBool IsDiv(nsIDOMNode *aNode);
|
||||
static PRBool IsNormalDiv(nsIDOMNode *aNode);
|
||||
static PRBool IsMozDiv(nsIDOMNode *aNode);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,8 @@
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "nsIPlaintextEditor.h"
|
||||
#include "nsPlaintextEditor.h"
|
||||
#include "nsIEditor.h"
|
||||
#include "nsIHTMLEditor.h"
|
||||
#include "nsITableEditor.h"
|
||||
#include "nsIEditorMailSupport.h"
|
||||
@ -51,8 +52,7 @@ class nsIDocumentEncoder;
|
||||
* The HTML editor implementation.<br>
|
||||
* Use to edit HTML document represented as a DOM tree.
|
||||
*/
|
||||
class nsHTMLEditor : public nsEditor,
|
||||
public nsIPlaintextEditor,
|
||||
class nsHTMLEditor : public nsPlaintextEditor,
|
||||
public nsIHTMLEditor,
|
||||
public nsIEditorMailSupport,
|
||||
public nsITableEditor,
|
||||
@ -74,7 +74,10 @@ public:
|
||||
kOpRemoveList = 3006,
|
||||
kOpMakeDefListItem = 3007,
|
||||
kOpInsertElement = 3008,
|
||||
kOpInsertQuotation = 3009
|
||||
kOpInsertQuotation = 3009,
|
||||
kOpSetTextProperty = 3010,
|
||||
kOpRemoveTextProperty = 3011,
|
||||
kOpHTMLPaste = 3012
|
||||
};
|
||||
|
||||
|
||||
@ -89,8 +92,9 @@ public:
|
||||
nsHTMLEditor();
|
||||
virtual ~nsHTMLEditor();
|
||||
|
||||
/* ------------ nsIPlaintextEditor methods -------------- */
|
||||
NS_DECL_NSIPLAINTEXTEDITOR
|
||||
/* ------------ nsPlaintextEditor overrides -------------- */
|
||||
NS_IMETHODIMP HandleKeyPress(nsIDOMKeyEvent* aKeyEvent);
|
||||
NS_IMETHODIMP CollapseSelectionToStart();
|
||||
|
||||
/* ------------ nsIHTMLEditor methods -------------- */
|
||||
NS_IMETHOD SetInlineProperty(nsIAtom *aProperty,
|
||||
@ -118,7 +122,6 @@ public:
|
||||
NS_IMETHOD RebuildDocumentFromSource(const nsString& aSourceString);
|
||||
NS_IMETHOD InsertElementAtSelection(nsIDOMElement* aElement, PRBool aDeleteSelection);
|
||||
|
||||
NS_IMETHOD DeleteSelectionAndCreateNode(const nsString& aTag, nsIDOMNode ** aNewNode);
|
||||
NS_IMETHOD SelectElement(nsIDOMElement* aElement);
|
||||
NS_IMETHOD SetCaretAfterElement(nsIDOMElement* aElement);
|
||||
|
||||
@ -240,12 +243,6 @@ public:
|
||||
/** prepare the editor for use */
|
||||
NS_IMETHOD Init(nsIDOMDocument *aDoc, nsIPresShell *aPresShell, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags);
|
||||
|
||||
NS_IMETHOD GetDocumentIsEmpty(PRBool *aDocumentIsEmpty);
|
||||
|
||||
NS_IMETHOD DeleteSelection(EDirection aAction);
|
||||
|
||||
NS_IMETHOD SetDocumentCharacterSet(const PRUnichar* characterSet);
|
||||
|
||||
/** we override this here to install event listeners */
|
||||
NS_IMETHOD PostCreate();
|
||||
|
||||
@ -266,15 +263,6 @@ public:
|
||||
NS_IMETHOD DoDrag(nsIDOMEvent *aDragEvent);
|
||||
NS_IMETHOD InsertFromDrop(nsIDOMEvent* aDropEvent);
|
||||
|
||||
NS_IMETHOD OutputToString(nsAWritableString& aOutputString,
|
||||
const nsAReadableString& aFormatType,
|
||||
PRUint32 aFlags);
|
||||
|
||||
NS_IMETHOD OutputToStream(nsIOutputStream* aOutputStream,
|
||||
const nsAReadableString& aFormatType,
|
||||
const nsAReadableString* aCharsetOverride,
|
||||
PRUint32 aFlags);
|
||||
|
||||
NS_IMETHOD GetHeadContentsAsHTML(nsString& aOutputString);
|
||||
NS_IMETHOD ReplaceHeadContentsWithHTML(const nsString &aSourceToInsert);
|
||||
|
||||
@ -307,7 +295,6 @@ public:
|
||||
PRInt32 aOffset,
|
||||
PRBool aNoEmptyNodes);
|
||||
|
||||
NS_IMETHOD GetBodyStyleContext(nsIStyleContext** aStyleContext);
|
||||
|
||||
/** returns the absolute position of the end points of aSelection
|
||||
* in the document as a text stream.
|
||||
@ -356,8 +343,6 @@ protected:
|
||||
*/
|
||||
NS_IMETHOD GetLayoutObject(nsIDOMNode *aInNode, nsISupports **aOutLayoutObject);
|
||||
|
||||
NS_IMETHOD DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNode> &parentSelectedNode, PRInt32& offsetOfNewNode);
|
||||
|
||||
/* StyleSheet load callback */
|
||||
static void ApplyStyleSheetToPresShellDocument(nsICSSStyleSheet* aSheet, void *aData);
|
||||
|
||||
@ -376,11 +361,11 @@ protected:
|
||||
// key event helpers
|
||||
NS_IMETHOD TabInTable(PRBool inIsShift, PRBool *outHandled);
|
||||
NS_IMETHOD CreateBR(nsIDOMNode *aNode, PRInt32 aOffset,
|
||||
nsCOMPtr<nsIDOMNode> *outBRNode, EDirection aSelect = eNone);
|
||||
nsCOMPtr<nsIDOMNode> *outBRNode, nsIEditor::EDirection aSelect = nsIEditor::eNone);
|
||||
NS_IMETHOD CreateBRImpl(nsCOMPtr<nsIDOMNode> *aInOutParent,
|
||||
PRInt32 *aInOutOffset,
|
||||
nsCOMPtr<nsIDOMNode> *outBRNode,
|
||||
EDirection aSelect);
|
||||
nsIEditor::EDirection aSelect);
|
||||
NS_IMETHOD InsertBR(nsCOMPtr<nsIDOMNode> *outBRNode);
|
||||
|
||||
// Table Editing (implemented in nsTableEditor.cpp)
|
||||
@ -491,12 +476,6 @@ protected:
|
||||
PRInt32 aEndOffset,
|
||||
nsISelection *aSelection);
|
||||
|
||||
// Helpers for output routines
|
||||
NS_IMETHOD GetAndInitDocEncoder(const nsAReadableString& aFormatType,
|
||||
PRUint32 aFlags,
|
||||
const nsAReadableString* aCharset,
|
||||
nsIDocumentEncoder** encoder);
|
||||
|
||||
// Methods for handling plaintext quotations
|
||||
NS_IMETHOD PasteAsPlaintextQuotation(PRInt32 aSelectionType);
|
||||
NS_IMETHOD InsertAsPlaintextQuotation(const nsString& aQuotedText,
|
||||
@ -610,38 +589,24 @@ protected:
|
||||
// Data members
|
||||
protected:
|
||||
|
||||
TypeInState* mTypeInState;
|
||||
nsCOMPtr<nsIEditRules> mRules;
|
||||
nsCOMPtr<nsIDOMEventListener> mKeyListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mMouseListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mTextListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mCompositionListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mDragListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mFocusListenerP;
|
||||
PRBool mIsComposing;
|
||||
|
||||
// Used by nsIPlaintextEditor but not html editors -- factor me!
|
||||
PRInt32 mMaxTextLength;
|
||||
TypeInState* mTypeInState;
|
||||
|
||||
nsCOMPtr<nsIAtom> mBoldAtom;
|
||||
nsCOMPtr<nsIAtom> mItalicAtom;
|
||||
nsCOMPtr<nsIAtom> mUnderlineAtom;
|
||||
nsCOMPtr<nsIAtom> mFontAtom;
|
||||
nsCOMPtr<nsIAtom> mLinkAtom;
|
||||
nsCOMPtr<nsIAtom> mBoldAtom;
|
||||
nsCOMPtr<nsIAtom> mItalicAtom;
|
||||
nsCOMPtr<nsIAtom> mUnderlineAtom;
|
||||
nsCOMPtr<nsIAtom> mFontAtom;
|
||||
nsCOMPtr<nsIAtom> mLinkAtom;
|
||||
nsCOMPtr<nsIDOMNode> mCachedNode;
|
||||
|
||||
PRBool mCachedBoldStyle;
|
||||
PRBool mCachedItalicStyle;
|
||||
PRBool mCachedUnderlineStyle;
|
||||
PRBool mCachedBoldStyle;
|
||||
PRBool mCachedItalicStyle;
|
||||
PRBool mCachedUnderlineStyle;
|
||||
nsString mCachedFontName;
|
||||
|
||||
// Used by GetFirstSelectedCell and GetNextSelectedCell
|
||||
PRInt32 mSelectedCellIndex;
|
||||
|
||||
public:
|
||||
static nsIAtom *gTypingTxnName;
|
||||
static nsIAtom *gIMETxnName;
|
||||
static nsIAtom *gDeleteTxnName;
|
||||
|
||||
// friends
|
||||
friend class nsHTMLEditRules;
|
||||
|
1486
editor/base/nsHTMLEditorStyle.cpp
Normal file
1486
editor/base/nsHTMLEditorStyle.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -28,6 +28,8 @@
|
||||
0xa6cf9121, 0x15b3, 0x11d2, \
|
||||
{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} }
|
||||
|
||||
#include "nsIHTMLEditor.h"
|
||||
|
||||
class nsIHTMLEditRules : public nsISupports
|
||||
{
|
||||
public:
|
||||
|
582
editor/base/nsPlaintextDataTransfer.cpp
Normal file
582
editor/base/nsPlaintextDataTransfer.cpp
Normal file
@ -0,0 +1,582 @@
|
||||
/* -*- 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.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
#include "nsICaret.h"
|
||||
|
||||
|
||||
#include "nsPlaintextEditor.h"
|
||||
#include "nsHTMLEditUtils.h"
|
||||
|
||||
#include "nsEditorEventListeners.h"
|
||||
|
||||
#include "nsIDOMText.h"
|
||||
#include "nsIDOMNodeList.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMAttr.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMEventReceiver.h"
|
||||
#include "nsIDOMKeyEvent.h"
|
||||
#include "nsIDOMKeyListener.h"
|
||||
#include "nsIDOMMouseListener.h"
|
||||
#include "nsIDOMMouseEvent.h"
|
||||
#include "nsISelection.h"
|
||||
#include "nsISelectionPrivate.h"
|
||||
#include "nsIDOMHTMLAnchorElement.h"
|
||||
#include "nsIDOMHTMLImageElement.h"
|
||||
#include "nsISelectionController.h"
|
||||
|
||||
#include "nsIFrameSelection.h" // For TABLESELECTION_ defines
|
||||
#include "nsIIndependentSelection.h" //domselections answer to frameselection
|
||||
|
||||
|
||||
#include "nsICSSLoader.h"
|
||||
#include "nsICSSStyleSheet.h"
|
||||
#include "nsIHTMLContentContainer.h"
|
||||
#include "nsIStyleSet.h"
|
||||
#include "nsIDocumentObserver.h"
|
||||
#include "nsIDocumentStateListener.h"
|
||||
|
||||
#include "nsIStyleContext.h"
|
||||
|
||||
#include "nsIEnumerator.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIContentIterator.h"
|
||||
#include "nsEditorCID.h"
|
||||
#include "nsLayoutCID.h"
|
||||
#include "nsIDOMRange.h"
|
||||
#include "nsIDOMNSRange.h"
|
||||
#include "nsISupportsArray.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsFileSpec.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsWidgetsCID.h"
|
||||
#include "nsIDocumentEncoder.h"
|
||||
#include "nsIDOMDocumentFragment.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsIParser.h"
|
||||
#include "nsParserCIID.h"
|
||||
#include "nsIImage.h"
|
||||
#include "nsAOLCiter.h"
|
||||
#include "nsInternetCiter.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "InsertTextTxn.h"
|
||||
|
||||
// netwerk
|
||||
#include "nsIURI.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
// Drag & Drop, Clipboard
|
||||
#include "nsWidgetsCID.h"
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsITransferable.h"
|
||||
#include "nsIDragService.h"
|
||||
#include "nsIDOMNSUIEvent.h"
|
||||
|
||||
// Transactionas
|
||||
#include "PlaceholderTxn.h"
|
||||
#include "nsStyleSheetTxns.h"
|
||||
|
||||
// Misc
|
||||
#include "TextEditorTest.h"
|
||||
#include "nsEditorUtils.h"
|
||||
#include "nsIPref.h"
|
||||
const PRUnichar nbsp = 160;
|
||||
|
||||
// HACK - CID for NS_CTRANSITIONAL_DTD_CID so that we can get at transitional dtd
|
||||
#define NS_CTRANSITIONAL_DTD_CID \
|
||||
{ 0x4611d482, 0x960a, 0x11d4, { 0x8e, 0xb0, 0xb6, 0x17, 0x66, 0x1b, 0x6f, 0x7c } }
|
||||
|
||||
|
||||
static NS_DEFINE_CID(kHTMLEditorCID, NS_HTMLEDITOR_CID);
|
||||
static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID);
|
||||
static NS_DEFINE_IID(kSubtreeIteratorCID, NS_SUBTREEITERATOR_CID);
|
||||
static NS_DEFINE_CID(kCRangeCID, NS_RANGE_CID);
|
||||
static NS_DEFINE_CID(kCDOMSelectionCID, NS_DOMSELECTION_CID);
|
||||
static NS_DEFINE_IID(kFileWidgetCID, NS_FILEWIDGET_CID);
|
||||
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
|
||||
static NS_DEFINE_IID(kCParserIID, NS_IPARSER_IID);
|
||||
static NS_DEFINE_IID(kCParserCID, NS_PARSER_IID);
|
||||
static NS_DEFINE_CID(kCTransitionalDTDCID, NS_CTRANSITIONAL_DTD_CID);
|
||||
|
||||
// Drag & Drop, Clipboard Support
|
||||
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
|
||||
static NS_DEFINE_CID(kCTransferableCID, NS_TRANSFERABLE_CID);
|
||||
static NS_DEFINE_CID(kCDragServiceCID, NS_DRAGSERVICE_CID);
|
||||
static NS_DEFINE_CID(kCHTMLFormatConverterCID, NS_HTMLFORMATCONVERTER_CID);
|
||||
// private clipboard data flavors for html copy/paste
|
||||
#define kHTMLContext "text/_moz_htmlcontext"
|
||||
#define kHTMLInfo "text/_moz_htmlinfo"
|
||||
|
||||
|
||||
#if defined(NS_DEBUG) && defined(DEBUG_buster)
|
||||
static PRBool gNoisy = PR_FALSE;
|
||||
#else
|
||||
static const PRBool gNoisy = PR_FALSE;
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP nsPlaintextEditor::PrepareTransferable(nsITransferable **transferable)
|
||||
{
|
||||
// Create generic Transferable for getting the data
|
||||
nsresult rv = nsComponentManager::CreateInstance(kCTransferableCID, nsnull,
|
||||
NS_GET_IID(nsITransferable),
|
||||
(void**)transferable);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Get the nsITransferable interface for getting the data from the clipboard
|
||||
if (transferable) (*transferable)->AddDataFlavor(kUnicodeMime);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPlaintextEditor::InsertTextFromTransferable(nsITransferable *transferable)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
char* bestFlavor = nsnull;
|
||||
nsCOMPtr<nsISupports> genericDataObj;
|
||||
PRUint32 len = 0;
|
||||
if ( NS_SUCCEEDED(transferable->GetAnyTransferData(&bestFlavor, getter_AddRefs(genericDataObj), &len)) )
|
||||
{
|
||||
nsAutoTxnsConserveSelection dontSpazMySelection(this);
|
||||
nsAutoString flavor, stuffToPaste;
|
||||
flavor.AssignWithConversion( bestFlavor ); // just so we can use flavor.Equals()
|
||||
if (flavor.EqualsWithConversion(kUnicodeMime))
|
||||
{
|
||||
nsCOMPtr<nsISupportsWString> textDataObj ( do_QueryInterface(genericDataObj) );
|
||||
if (textDataObj && len > 0)
|
||||
{
|
||||
PRUnichar* text = nsnull;
|
||||
textDataObj->ToString ( &text );
|
||||
stuffToPaste.Assign ( text, len / 2 );
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
rv = InsertText(stuffToPaste.GetUnicode());
|
||||
if (text)
|
||||
nsMemory::Free(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
nsCRT::free(bestFlavor);
|
||||
|
||||
// Try to scroll the selection into view if the paste/drop succeeded
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
if (NS_SUCCEEDED(GetSelectionController(getter_AddRefs(selCon))) && selCon)
|
||||
selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, nsISelectionController::SELECTION_FOCUS_REGION);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPlaintextEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
|
||||
{
|
||||
ForceCompositionEnd();
|
||||
|
||||
nsresult rv;
|
||||
NS_WITH_SERVICE(nsIDragService, dragService, "@mozilla.org/widget/dragservice;1", &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIDragSession> dragSession(do_QueryInterface(dragService));
|
||||
|
||||
if (!dragSession) return NS_OK;
|
||||
|
||||
// Get the nsITransferable interface for getting the data from the drop
|
||||
nsCOMPtr<nsITransferable> trans;
|
||||
rv = PrepareTransferable(getter_AddRefs(trans));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!trans) return NS_OK; // NS_ERROR_FAILURE; SHOULD WE FAIL?
|
||||
|
||||
PRUint32 numItems = 0;
|
||||
rv = dragSession->GetNumDropItems(&numItems);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Combine any deletion and drop insertion into one transaction
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
|
||||
PRUint32 i;
|
||||
PRBool doPlaceCaret = PR_TRUE;
|
||||
for (i = 0; i < numItems; ++i)
|
||||
{
|
||||
rv = dragSession->GetData(trans, i);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!trans) return NS_OK; // NS_ERROR_FAILURE; Should we fail?
|
||||
|
||||
if ( doPlaceCaret )
|
||||
{
|
||||
// check if the user pressed the key to force a copy rather than a move
|
||||
// if we run into problems here, we'll just assume the user doesn't want a copy
|
||||
PRBool userWantsCopy = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIDOMNSUIEvent> nsuiEvent (do_QueryInterface(aDropEvent));
|
||||
if (!nsuiEvent) return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aDropEvent) );
|
||||
if (mouseEvent)
|
||||
|
||||
#ifdef XP_MAC
|
||||
mouseEvent->GetAltKey(&userWantsCopy);
|
||||
#else
|
||||
mouseEvent->GetCtrlKey(&userWantsCopy);
|
||||
#endif
|
||||
// Source doc is null if source is *not* the current editor document
|
||||
nsCOMPtr<nsIDOMDocument> srcdomdoc;
|
||||
rv = dragSession->GetSourceDocument(getter_AddRefs(srcdomdoc));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Current doc is destination
|
||||
nsCOMPtr<nsIDOMDocument>destdomdoc;
|
||||
rv = GetDocument(getter_AddRefs(destdomdoc));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
rv = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!selection) return NS_ERROR_FAILURE;
|
||||
|
||||
PRBool isCollapsed;
|
||||
rv = selection->GetIsCollapsed(&isCollapsed);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Parent and offset under the mouse cursor
|
||||
nsCOMPtr<nsIDOMNode> newSelectionParent;
|
||||
PRInt32 newSelectionOffset = 0;
|
||||
rv = nsuiEvent->GetRangeParent(getter_AddRefs(newSelectionParent));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!newSelectionParent) return NS_ERROR_FAILURE;
|
||||
|
||||
rv = nsuiEvent->GetRangeOffset(&newSelectionOffset);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
/* Creating a range to store insert position because when
|
||||
we delete the selection, range gravity will make sure the insertion
|
||||
point is in the correct place */
|
||||
nsCOMPtr<nsIDOMRange> destinationRange;
|
||||
rv = CreateRange(newSelectionParent, newSelectionOffset,newSelectionParent, newSelectionOffset, getter_AddRefs(destinationRange));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
if(!destinationRange)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// We never have to delete if selection is already collapsed
|
||||
PRBool deleteSelection = PR_FALSE;
|
||||
PRBool cursorIsInSelection = PR_FALSE;
|
||||
|
||||
// Check if mouse is in the selection
|
||||
if (!isCollapsed)
|
||||
{
|
||||
PRInt32 rangeCount;
|
||||
rv = selection->GetRangeCount(&rangeCount);
|
||||
if (NS_FAILED(rv))
|
||||
return rv?rv:NS_ERROR_FAILURE;
|
||||
|
||||
for (PRInt32 j = 0; j < rangeCount; j++)
|
||||
{
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
|
||||
rv = selection->GetRangeAt(j, getter_AddRefs(range));
|
||||
if (NS_FAILED(rv) || !range)
|
||||
continue;//dont bail yet, iterate through them all
|
||||
|
||||
nsCOMPtr<nsIDOMNSRange> nsrange(do_QueryInterface(range));
|
||||
if (NS_FAILED(rv) || !nsrange)
|
||||
continue;//dont bail yet, iterate through them all
|
||||
|
||||
rv = nsrange->IsPointInRange(newSelectionParent, newSelectionOffset, &cursorIsInSelection);
|
||||
if(cursorIsInSelection)
|
||||
break;
|
||||
}
|
||||
if (cursorIsInSelection)
|
||||
{
|
||||
// Dragging within same doc can't drop on itself -- leave!
|
||||
// (We shouldn't get here - drag event shouldn't have started if over selection)
|
||||
if (srcdomdoc == destdomdoc)
|
||||
return NS_OK;
|
||||
|
||||
// Dragging from another window onto a selection
|
||||
// XXX Decision made to NOT do this,
|
||||
// note that 4.x does replace if dropped on
|
||||
//deleteSelection = PR_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are NOT over the selection
|
||||
if (srcdomdoc == destdomdoc)
|
||||
{
|
||||
// Within the same doc: delete if user doesn't want to copy
|
||||
deleteSelection = !userWantsCopy;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Different source doc: Don't delete
|
||||
deleteSelection = PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deleteSelection)
|
||||
{
|
||||
rv = DeleteSelection(eNone);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// If we deleted the selection because we dropped from another doc,
|
||||
// then we don't have to relocate the caret (insert at the deletion point)
|
||||
if (!(deleteSelection && srcdomdoc != destdomdoc))
|
||||
{
|
||||
// Move the selection to the point under the mouse cursor
|
||||
rv = destinationRange->GetStartContainer(getter_AddRefs(newSelectionParent));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
if(!newSelectionParent)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
rv = destinationRange->GetStartOffset(&newSelectionOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
selection->Collapse(newSelectionParent, newSelectionOffset);
|
||||
}
|
||||
// We have to figure out whether to delete and relocate caret only once
|
||||
doPlaceCaret = PR_FALSE;
|
||||
}
|
||||
|
||||
rv = InsertTextFromTransferable(trans);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPlaintextEditor::CanDrag(nsIDOMEvent *aDragEvent, PRBool &aCanDrag)
|
||||
{
|
||||
/* we really should be checking the XY coordinates of the mouseevent and ensure that
|
||||
* that particular point is actually within the selection (not just that there is a selection)
|
||||
*/
|
||||
aCanDrag = PR_FALSE;
|
||||
|
||||
// KLUDGE to work around bug 50703
|
||||
// After double click and object property editing,
|
||||
// we get a spurious drag event
|
||||
if (mIgnoreSpuriousDragEvent)
|
||||
{
|
||||
mIgnoreSpuriousDragEvent = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
nsresult res = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
PRBool isCollapsed;
|
||||
res = selection->GetIsCollapsed(&isCollapsed);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// if we are collapsed, we have no selection so nothing to drag
|
||||
if ( isCollapsed )
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> eventTarget;
|
||||
res = aDragEvent->GetOriginalTarget(getter_AddRefs(eventTarget));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if ( eventTarget )
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> eventTargetDomNode = do_QueryInterface(eventTarget);
|
||||
if ( eventTargetDomNode )
|
||||
{
|
||||
PRBool amTargettedCorrectly = PR_FALSE;
|
||||
res = selection->ContainsNode(eventTargetDomNode, PR_FALSE, &amTargettedCorrectly);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
aCanDrag = amTargettedCorrectly;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPlaintextEditor::DoDrag(nsIDOMEvent *aDragEvent)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> eventTarget;
|
||||
rv = aDragEvent->GetTarget(getter_AddRefs(eventTarget));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
nsCOMPtr<nsIDOMNode> domnode = do_QueryInterface(eventTarget);
|
||||
|
||||
/* get the selection to be dragged */
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
rv = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
/* create an array of transferables */
|
||||
nsCOMPtr<nsISupportsArray> transferableArray;
|
||||
NS_NewISupportsArray(getter_AddRefs(transferableArray));
|
||||
if (transferableArray == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
/* get the drag service */
|
||||
NS_WITH_SERVICE(nsIDragService, dragService, "@mozilla.org/widget/dragservice;1", &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
/* create html flavor transferable */
|
||||
nsCOMPtr<nsITransferable> trans;
|
||||
rv = nsComponentManager::CreateInstance(kCTransferableCID, nsnull,
|
||||
NS_GET_IID(nsITransferable),
|
||||
getter_AddRefs(trans));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if ( !trans ) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> domdoc;
|
||||
rv = GetDocument(getter_AddRefs(domdoc));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
|
||||
if (doc)
|
||||
{
|
||||
nsCOMPtr<nsIDocumentEncoder> docEncoder;
|
||||
|
||||
docEncoder = do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "text/html");
|
||||
NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE);
|
||||
|
||||
docEncoder->Init(doc, NS_LITERAL_STRING("text/html"), 0);
|
||||
docEncoder->SetSelection(selection);
|
||||
|
||||
nsAutoString buffer;
|
||||
|
||||
rv = docEncoder->EncodeToString(buffer);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if ( !buffer.IsEmpty() )
|
||||
{
|
||||
nsCOMPtr<nsIFormatConverter> htmlConverter;
|
||||
rv = nsComponentManager::CreateInstance(kCHTMLFormatConverterCID, nsnull, NS_GET_IID(nsIFormatConverter),
|
||||
getter_AddRefs(htmlConverter));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!htmlConverter) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsCOMPtr<nsISupportsWString> dataWrapper;
|
||||
rv = nsComponentManager::CreateInstance(NS_SUPPORTS_WSTRING_CONTRACTID, nsnull,
|
||||
NS_GET_IID(nsISupportsWString), getter_AddRefs(dataWrapper));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if ( !dataWrapper ) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
rv = trans->AddDataFlavor(kHTMLMime);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = trans->SetConverter(htmlConverter);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = dataWrapper->SetData( NS_CONST_CAST(PRUnichar*, buffer.GetUnicode()) );
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// QI the data object an |nsISupports| so that when the transferable holds
|
||||
// onto it, it will addref the correct interface.
|
||||
nsCOMPtr<nsISupports> nsisupportsDataWrapper ( do_QueryInterface(dataWrapper) );
|
||||
rv = trans->SetTransferData(kHTMLMime, nsisupportsDataWrapper, buffer.Length() * 2);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
/* add the transferable to the array */
|
||||
rv = transferableArray->AppendElement(trans);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
/* invoke drag */
|
||||
unsigned int flags;
|
||||
// in some cases we'll want to cut rather than copy... hmmmmm...
|
||||
// if ( wantToCut )
|
||||
// flags = nsIDragService.DRAGDROP_ACTION_COPY + nsIDragService.DRAGDROP_ACTION_MOVE;
|
||||
// else
|
||||
flags = nsIDragService::DRAGDROP_ACTION_COPY + nsIDragService::DRAGDROP_ACTION_MOVE;
|
||||
|
||||
rv = dragService->InvokeDragSession( domnode, transferableArray, nsnull, flags);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
aDragEvent->PreventBubble();
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPlaintextEditor::Paste(PRInt32 aSelectionType)
|
||||
{
|
||||
ForceCompositionEnd();
|
||||
|
||||
// Get Clipboard Service
|
||||
nsresult rv;
|
||||
NS_WITH_SERVICE ( nsIClipboard, clipboard, kCClipboardCID, &rv );
|
||||
if ( NS_FAILED(rv) )
|
||||
return rv;
|
||||
|
||||
// Get the nsITransferable interface for getting the data from the clipboard
|
||||
nsCOMPtr<nsITransferable> trans;
|
||||
rv = PrepareTransferable(getter_AddRefs(trans));
|
||||
if (NS_SUCCEEDED(rv) && trans)
|
||||
{
|
||||
// Get the Data from the clipboard
|
||||
if (NS_SUCCEEDED(clipboard->GetData(trans, aSelectionType)) && IsModifiable())
|
||||
{
|
||||
rv = InsertTextFromTransferable(trans);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsPlaintextEditor::CanPaste(PRInt32 aSelectionType, PRBool &aCanPaste)
|
||||
{
|
||||
aCanPaste = PR_FALSE;
|
||||
|
||||
nsresult rv;
|
||||
NS_WITH_SERVICE(nsIClipboard, clipboard, kCClipboardCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// the flavors that we can deal with
|
||||
char* textEditorFlavors[] = { kUnicodeMime, nsnull };
|
||||
|
||||
nsCOMPtr<nsISupportsArray> flavorsList;
|
||||
rv = nsComponentManager::CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, nsnull,
|
||||
NS_GET_IID(nsISupportsArray), getter_AddRefs(flavorsList));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRUint32 editorFlags;
|
||||
GetFlags(&editorFlags);
|
||||
|
||||
// add the flavors for text editors
|
||||
for (char** flavor = textEditorFlavors; *flavor; flavor++)
|
||||
{
|
||||
nsCOMPtr<nsISupportsString> flavorString;
|
||||
nsComponentManager::CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, nsnull,
|
||||
NS_GET_IID(nsISupportsString), getter_AddRefs(flavorString));
|
||||
if (flavorString)
|
||||
{
|
||||
flavorString->SetData(*flavor);
|
||||
flavorsList->AppendElement(flavorString);
|
||||
}
|
||||
}
|
||||
|
||||
PRBool haveFlavors;
|
||||
rv = clipboard->HasDataMatchingFlavors(flavorsList, aSelectionType, &haveFlavors);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
aCanPaste = haveFlavors;
|
||||
return NS_OK;
|
||||
}
|
1808
editor/base/nsPlaintextEditor.cpp
Normal file
1808
editor/base/nsPlaintextEditor.cpp
Normal file
File diff suppressed because it is too large
Load Diff
228
editor/base/nsPlaintextEditor.h
Normal file
228
editor/base/nsPlaintextEditor.h
Normal file
@ -0,0 +1,228 @@
|
||||
/* -*- 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.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#ifndef nsPlaintextEditor_h__
|
||||
#define nsPlaintextEditor_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "nsIPlaintextEditor.h"
|
||||
|
||||
#include "nsEditor.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
|
||||
#include "TypeInState.h"
|
||||
#include "nsEditRules.h"
|
||||
|
||||
class nsIDOMKeyEvent;
|
||||
class nsITransferable;
|
||||
class nsIDOMEventReceiver;
|
||||
class nsIDocumentEncoder;
|
||||
|
||||
/**
|
||||
* The text editor implementation.
|
||||
* Use to edit text document represented as a DOM tree.
|
||||
*/
|
||||
class nsPlaintextEditor : public nsEditor,
|
||||
public nsIPlaintextEditor
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// Interfaces for addref and release and queryinterface
|
||||
// NOTE macro used is for classes that inherit from
|
||||
// another class. Only the base class should use NS_DECL_ISUPPORTS
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
/* below used by TypedText() */
|
||||
enum {
|
||||
eTypedText, /* user typed text */
|
||||
eTypedBR, /* user typed shift-enter to get a br */
|
||||
eTypedBreak /* user typed enter */
|
||||
};
|
||||
|
||||
nsPlaintextEditor();
|
||||
virtual ~nsPlaintextEditor();
|
||||
|
||||
/* ------------ nsIPlaintextEditor methods -------------- */
|
||||
NS_DECL_NSIPLAINTEXTEDITOR
|
||||
|
||||
/* ------------ nsIEditorIMESupport overrides -------------- */
|
||||
|
||||
NS_IMETHOD SetCompositionString(const nsString& aCompositionString, nsIPrivateTextRangeList* aTextRangeList,nsTextEventReply* aReply);
|
||||
NS_IMETHOD GetReconversionString(nsReconversionEventReply* aReply);
|
||||
|
||||
/* ------------ Overrides of nsEditor interface methods -------------- */
|
||||
|
||||
/** prepare the editor for use */
|
||||
NS_IMETHOD Init(nsIDOMDocument *aDoc, nsIPresShell *aPresShell, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags);
|
||||
|
||||
NS_IMETHOD GetDocumentIsEmpty(PRBool *aDocumentIsEmpty);
|
||||
|
||||
NS_IMETHOD DeleteSelection(EDirection aAction);
|
||||
|
||||
NS_IMETHOD SetDocumentCharacterSet(const PRUnichar* characterSet);
|
||||
|
||||
/** we override this here to install event listeners */
|
||||
NS_IMETHOD PostCreate();
|
||||
|
||||
NS_IMETHOD GetFlags(PRUint32 *aFlags);
|
||||
NS_IMETHOD SetFlags(PRUint32 aFlags);
|
||||
|
||||
NS_IMETHOD Undo(PRUint32 aCount);
|
||||
NS_IMETHOD Redo(PRUint32 aCount);
|
||||
|
||||
NS_IMETHOD Cut();
|
||||
NS_IMETHOD CanCut(PRBool &aCanCut);
|
||||
NS_IMETHOD Copy();
|
||||
NS_IMETHOD CanCopy(PRBool &aCanCopy);
|
||||
NS_IMETHOD Paste(PRInt32 aSelectionType);
|
||||
NS_IMETHOD CanPaste(PRInt32 aSelectionType, PRBool &aCanPaste);
|
||||
|
||||
NS_IMETHOD CanDrag(nsIDOMEvent *aDragEvent, PRBool &aCanDrag);
|
||||
NS_IMETHOD DoDrag(nsIDOMEvent *aDragEvent);
|
||||
NS_IMETHOD InsertFromDrop(nsIDOMEvent* aDropEvent);
|
||||
|
||||
NS_IMETHOD OutputToString(nsAWritableString& aOutputString,
|
||||
const nsAReadableString& aFormatType,
|
||||
PRUint32 aFlags);
|
||||
|
||||
NS_IMETHOD OutputToStream(nsIOutputStream* aOutputStream,
|
||||
const nsAReadableString& aFormatType,
|
||||
const nsAReadableString* aCharsetOverride,
|
||||
PRUint32 aFlags);
|
||||
|
||||
|
||||
/** All editor operations which alter the doc should be prefaced
|
||||
* with a call to StartOperation, naming the action and direction */
|
||||
NS_IMETHOD StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
|
||||
|
||||
/** All editor operations which alter the doc should be followed
|
||||
* with a call to EndOperation */
|
||||
NS_IMETHOD EndOperation();
|
||||
|
||||
/** make the given selection span the entire document */
|
||||
NS_IMETHOD SelectEntireDocument(nsISelection *aSelection);
|
||||
|
||||
/* ------------ Utility Routines, not part of public API -------------- */
|
||||
NS_IMETHOD TypedText(const PRUnichar* aString, PRInt32 aAction);
|
||||
|
||||
/** returns the absolute position of the end points of aSelection
|
||||
* in the document as a text stream.
|
||||
*/
|
||||
nsresult GetTextSelectionOffsets(nsISelection *aSelection,
|
||||
PRInt32 &aStartOffset,
|
||||
PRInt32 &aEndOffset);
|
||||
|
||||
nsresult GetAbsoluteOffsetsForPoints(nsIDOMNode *aInStartNode,
|
||||
PRInt32 aInStartOffset,
|
||||
nsIDOMNode *aInEndNode,
|
||||
PRInt32 aInEndOffset,
|
||||
nsIDOMNode *aInCommonParentNode,
|
||||
PRInt32 &aOutStartOffset,
|
||||
PRInt32 &aEndOffset);
|
||||
|
||||
protected:
|
||||
|
||||
NS_IMETHOD InitRules();
|
||||
void BeginEditorInit();
|
||||
nsresult EndEditorInit();
|
||||
|
||||
/** install the event listeners for the editor
|
||||
* used to be part of Init, but now broken out into a separate method
|
||||
* called by PostCreate, giving the caller the chance to interpose
|
||||
* their own listeners before we install our own backstops.
|
||||
*/
|
||||
NS_IMETHOD InstallEventListeners();
|
||||
|
||||
/** returns the layout object (nsIFrame in the real world) for aNode
|
||||
* @param aNode the content to get a frame for
|
||||
* @param aLayoutObject the "primary frame" for aNode, if one exists. May be null
|
||||
* @return NS_OK whether a frame is found or not
|
||||
* an error if some serious error occurs
|
||||
*/
|
||||
NS_IMETHOD GetLayoutObject(nsIDOMNode *aInNode, nsISupports **aOutLayoutObject);
|
||||
NS_IMETHOD GetBodyStyleContext(nsIStyleContext** aStyleContext);
|
||||
|
||||
// Helpers for output routines
|
||||
NS_IMETHOD GetAndInitDocEncoder(const nsAReadableString& aFormatType,
|
||||
PRUint32 aFlags,
|
||||
const nsAReadableString* aCharset,
|
||||
nsIDocumentEncoder** encoder);
|
||||
|
||||
// key event helpers
|
||||
NS_IMETHOD CreateBR(nsIDOMNode *aNode, PRInt32 aOffset,
|
||||
nsCOMPtr<nsIDOMNode> *outBRNode, EDirection aSelect = eNone);
|
||||
NS_IMETHOD CreateBRImpl(nsCOMPtr<nsIDOMNode> *aInOutParent,
|
||||
PRInt32 *aInOutOffset,
|
||||
nsCOMPtr<nsIDOMNode> *outBRNode,
|
||||
EDirection aSelect);
|
||||
NS_IMETHOD InsertBR(nsCOMPtr<nsIDOMNode> *outBRNode);
|
||||
|
||||
NS_IMETHOD IsRootTag(nsString &aTag, PRBool &aIsTag);
|
||||
|
||||
|
||||
// factored methods for handling insertion of data from transferables (drag&drop or clipboard)
|
||||
NS_IMETHOD PrepareTransferable(nsITransferable **transferable);
|
||||
NS_IMETHOD InsertTextFromTransferable(nsITransferable *transferable);
|
||||
|
||||
/** simple utility to handle any error with event listener allocation or registration */
|
||||
void HandleEventListenerError();
|
||||
|
||||
/* small utility routine to test the eEditorReadonly bit */
|
||||
PRBool IsModifiable();
|
||||
|
||||
nsresult GetDOMEventReceiver(nsIDOMEventReceiver **aEventReceiver);
|
||||
|
||||
//XXX Kludge: Used to suppress spurious drag/drop events (bug 50703)
|
||||
PRBool mIgnoreSpuriousDragEvent;
|
||||
NS_IMETHOD IgnoreSpuriousDragEvent(PRBool aIgnoreSpuriousDragEvent) {mIgnoreSpuriousDragEvent = aIgnoreSpuriousDragEvent; return NS_OK;}
|
||||
|
||||
// Data members
|
||||
protected:
|
||||
|
||||
nsCOMPtr<nsIEditRules> mRules;
|
||||
nsCOMPtr<nsIDOMEventListener> mKeyListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mMouseListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mTextListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mCompositionListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mDragListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mFocusListenerP;
|
||||
PRBool mIsComposing;
|
||||
PRInt32 mMaxTextLength;
|
||||
PRInt32 mInitTriggerCounter;
|
||||
|
||||
public:
|
||||
static nsIAtom *gTypingTxnName;
|
||||
static nsIAtom *gIMETxnName;
|
||||
static nsIAtom *gDeleteTxnName;
|
||||
|
||||
// friends
|
||||
friend class nsHTMLEditRules;
|
||||
friend class nsTextEditRules;
|
||||
friend class nsAutoEditInitRulesTrigger;
|
||||
|
||||
};
|
||||
|
||||
#endif //nsPlaintextEditor_h__
|
||||
|
640
editor/base/nsSelectionState.cpp
Normal file
640
editor/base/nsSelectionState.cpp
Normal file
@ -0,0 +1,640 @@
|
||||
/* -*- 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.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nsSelectionState.h"
|
||||
#include "nsIDOMCharacterData.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsIDOMRange.h"
|
||||
#include "nsISelection.h"
|
||||
#include "nsEditor.h"
|
||||
#include "nsLayoutCID.h"
|
||||
|
||||
static NS_DEFINE_CID(kCRangeCID, NS_RANGE_CID);
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* class for recording selection info. stores selection as collection of
|
||||
* { {startnode, startoffset} , {endnode, endoffset} } tuples. Cant store
|
||||
* ranges since dom gravity will possibly change the ranges.
|
||||
*/
|
||||
nsSelectionState::nsSelectionState() : mArray(){}
|
||||
|
||||
nsSelectionState::~nsSelectionState()
|
||||
{
|
||||
MakeEmpty();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSelectionState::SaveSelection(nsISelection *aSel)
|
||||
{
|
||||
if (!aSel) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
PRInt32 i,rangeCount, arrayCount = mArray.Count();
|
||||
nsRangeStore *item;
|
||||
aSel->GetRangeCount(&rangeCount);
|
||||
|
||||
// if we need more items in the array, new them
|
||||
if (arrayCount<rangeCount)
|
||||
{
|
||||
PRInt32 count = rangeCount-arrayCount;
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = new nsRangeStore;
|
||||
mArray.AppendElement(item);
|
||||
}
|
||||
}
|
||||
|
||||
// else if we have too many, delete them
|
||||
else if (rangeCount>arrayCount)
|
||||
{
|
||||
while ((item = (nsRangeStore*)mArray.ElementAt(rangeCount)))
|
||||
{
|
||||
delete item;
|
||||
mArray.RemoveElementAt(rangeCount);
|
||||
}
|
||||
}
|
||||
|
||||
// now store the selection ranges
|
||||
for (i=0; i<rangeCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_UNEXPECTED;
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
res = aSel->GetRangeAt(i, getter_AddRefs(range));
|
||||
item->StoreRange(range);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSelectionState::RestoreSelection(nsISelection *aSel)
|
||||
{
|
||||
if (!aSel) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
PRInt32 i, arrayCount = mArray.Count();
|
||||
nsRangeStore *item;
|
||||
|
||||
// clear out selection
|
||||
aSel->RemoveAllRanges();
|
||||
|
||||
// set the selection ranges anew
|
||||
for (i=0; i<arrayCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_UNEXPECTED;
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
item->GetRange(address_of(range));
|
||||
if (!range) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
res = aSel->AddRange(range);
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSelectionState::IsCollapsed()
|
||||
{
|
||||
if (1 != mArray.Count()) return PR_FALSE;
|
||||
nsRangeStore *item;
|
||||
item = (nsRangeStore*)mArray.ElementAt(0);
|
||||
if (!item) return PR_FALSE;
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
item->GetRange(address_of(range));
|
||||
if (!range) return PR_FALSE;
|
||||
PRBool bIsCollapsed;
|
||||
range->GetCollapsed(&bIsCollapsed);
|
||||
return bIsCollapsed;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSelectionState::IsEqual(nsSelectionState *aSelState)
|
||||
{
|
||||
if (!aSelState) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, myCount = mArray.Count(), itsCount = aSelState->mArray.Count();
|
||||
if (myCount != itsCount) return PR_FALSE;
|
||||
if (myCount < 1) return PR_FALSE;
|
||||
|
||||
nsRangeStore *myItem, *itsItem;
|
||||
|
||||
for (i=0; i<myCount; i++)
|
||||
{
|
||||
myItem = (nsRangeStore*)mArray.ElementAt(0);
|
||||
itsItem = (nsRangeStore*)(aSelState->mArray.ElementAt(0));
|
||||
if (!myItem || !itsItem) return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIDOMRange> myRange, itsRange;
|
||||
myItem->GetRange(address_of(myRange));
|
||||
itsItem->GetRange(address_of(itsRange));
|
||||
if (!myRange || !itsRange) return PR_FALSE;
|
||||
|
||||
PRInt32 compResult;
|
||||
myRange->CompareBoundaryPoints(nsIDOMRange::START_TO_START, itsRange, &compResult);
|
||||
if (compResult) return PR_FALSE;
|
||||
myRange->CompareBoundaryPoints(nsIDOMRange::END_TO_END, itsRange, &compResult);
|
||||
if (compResult) return PR_FALSE;
|
||||
}
|
||||
// if we got here, they are equal
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nsSelectionState::MakeEmpty()
|
||||
{
|
||||
// free any items in the array
|
||||
nsRangeStore *item;
|
||||
while ((item = (nsRangeStore*)mArray.ElementAt(0)))
|
||||
{
|
||||
delete item;
|
||||
mArray.RemoveElementAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSelectionState::IsEmpty()
|
||||
{
|
||||
return (mArray.Count() == 0);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* nsRangeUpdater: class for updating nsIDOMRanges in response to editor actions.
|
||||
*/
|
||||
|
||||
nsRangeUpdater::nsRangeUpdater() : mArray(), mLock(PR_FALSE) {}
|
||||
|
||||
nsRangeUpdater::~nsRangeUpdater()
|
||||
{
|
||||
// free any items in the array
|
||||
nsRangeStore *item;
|
||||
while ((item = (nsRangeStore*)mArray.ElementAt(0)))
|
||||
{
|
||||
delete item;
|
||||
mArray.RemoveElementAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
void*
|
||||
nsRangeUpdater::RegisterRange(nsIDOMRange *aRange)
|
||||
{
|
||||
nsRangeStore *item = new nsRangeStore;
|
||||
if (!item) return nsnull;
|
||||
item->StoreRange(aRange);
|
||||
mArray.AppendElement(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMRange>
|
||||
nsRangeUpdater::ReclaimRange(void *aCookie)
|
||||
{
|
||||
nsRangeStore *item = NS_STATIC_CAST(nsRangeStore*,aCookie);
|
||||
if (!item) return nsnull;
|
||||
nsCOMPtr<nsIDOMRange> outRange;
|
||||
item->GetRange(address_of(outRange));
|
||||
mArray.RemoveElement(aCookie);
|
||||
delete item;
|
||||
return outRange;
|
||||
}
|
||||
|
||||
void
|
||||
nsRangeUpdater::DropRange(void *aCookie)
|
||||
{
|
||||
nsRangeStore *item = NS_STATIC_CAST(nsRangeStore*,aCookie);
|
||||
if (!item) return;
|
||||
mArray.RemoveElement(aCookie);
|
||||
delete item;
|
||||
}
|
||||
|
||||
void
|
||||
nsRangeUpdater::RegisterRangeItem(nsRangeStore *aRangeItem)
|
||||
{
|
||||
if (!aRangeItem) return;
|
||||
mArray.AppendElement(aRangeItem);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
nsRangeUpdater::DropRangeItem(nsRangeStore *aRangeItem)
|
||||
{
|
||||
if (!aRangeItem) return;
|
||||
mArray.RemoveElement(aRangeItem);
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::RegisterSelectionState(nsSelectionState &aSelState)
|
||||
{
|
||||
PRInt32 i, theCount = aSelState.mArray.Count();
|
||||
if (theCount < 1) return NS_ERROR_FAILURE;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<theCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)aSelState.mArray.ElementAt(i);
|
||||
RegisterRangeItem(item);
|
||||
}
|
||||
|
||||
return NS_OK;;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DropSelectionState(nsSelectionState &aSelState)
|
||||
{
|
||||
PRInt32 i, theCount = aSelState.mArray.Count();
|
||||
if (theCount < 1) return NS_ERROR_FAILURE;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<theCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)aSelState.mArray.ElementAt(i);
|
||||
DropRangeItem(item);
|
||||
}
|
||||
|
||||
return NS_OK;;
|
||||
}
|
||||
|
||||
// gravity methods:
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjCreateNode(nsIDOMNode *aParent, PRInt32 aPosition)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if ((item->startNode.get() == aParent) && (item->startOffset > aPosition))
|
||||
item->startOffset++;
|
||||
if ((item->endNode.get() == aParent) && (item->endOffset > aPosition))
|
||||
item->endOffset++;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjInsertNode(nsIDOMNode *aParent, PRInt32 aPosition)
|
||||
{
|
||||
return SelAdjCreateNode(aParent, aPosition);
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjDeleteNode(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aNode) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if ((item->startNode.get() == aParent) && (item->startOffset > aOffset))
|
||||
item->startOffset--;
|
||||
if ((item->endNode.get() == aParent) && (item->endOffset > aOffset))
|
||||
item->endOffset--;
|
||||
}
|
||||
// MOOSE: also check inside of aNode, expensive. But in theory, we shouldn't
|
||||
// actually hit this case in the usage i forsee for this.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjSplitNode(nsIDOMNode *aOldRightNode, PRInt32 aOffset, nsIDOMNode *aNewLeftNode)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aOldRightNode || !aNewLeftNode) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> parent;
|
||||
PRInt32 offset;
|
||||
nsresult result = nsEditor::GetNodeLocation(aOldRightNode, address_of(parent), &offset);
|
||||
if (NS_FAILED(result)) return result;
|
||||
|
||||
// first part is same as inserting aNewLeftnode
|
||||
result = SelAdjInsertNode(parent,offset-1);
|
||||
if (NS_FAILED(result)) return result;
|
||||
|
||||
// next step is to check for range enpoints inside aOldRightNode
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (item->startNode.get() == aOldRightNode)
|
||||
{
|
||||
if (item->startOffset > aOffset)
|
||||
{
|
||||
item->startOffset -= aOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->startNode = aNewLeftNode;
|
||||
}
|
||||
}
|
||||
if (item->endNode.get() == aOldRightNode)
|
||||
{
|
||||
if (item->endOffset > aOffset)
|
||||
{
|
||||
item->endOffset -= aOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->endNode = aNewLeftNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjJoinNodes(nsIDOMNode *aLeftNode,
|
||||
nsIDOMNode *aRightNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aOffset,
|
||||
PRInt32 aOldLeftNodeLength)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aLeftNode || !aRightNode || !aParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// adjust endpoints in aParent
|
||||
if (item->startNode.get() == aParent)
|
||||
{
|
||||
if (item->startOffset > aOffset)
|
||||
{
|
||||
item->startOffset--;
|
||||
}
|
||||
else if (item->startOffset == aOffset)
|
||||
{
|
||||
// join keeps right hand node
|
||||
item->startNode = aRightNode;
|
||||
item->startOffset = aOldLeftNodeLength;
|
||||
}
|
||||
}
|
||||
if (item->endNode.get() == aParent)
|
||||
{
|
||||
if (item->endOffset > aOffset)
|
||||
{
|
||||
item->endOffset--;
|
||||
}
|
||||
else if (item->endOffset == aOffset)
|
||||
{
|
||||
// join keeps right hand node
|
||||
item->endNode = aRightNode;
|
||||
item->endOffset = aOldLeftNodeLength;
|
||||
}
|
||||
}
|
||||
// adjust endpoints in aRightNode
|
||||
if (item->startNode.get() == aRightNode)
|
||||
item->startOffset += aOldLeftNodeLength;
|
||||
if (item->endNode.get() == aRightNode)
|
||||
item->endOffset += aOldLeftNodeLength;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjInsertText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, const nsString &aString)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjDeleteText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, PRInt32 aLength)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillReplaceContainer()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidReplaceContainer(nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode)
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
|
||||
if (!aOriginalNode || !aNewNode) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (item->startNode.get() == aOriginalNode)
|
||||
item->startNode = aNewNode;
|
||||
if (item->endNode.get() == aOriginalNode)
|
||||
item->endNode = aNewNode;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillRemoveContainer()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidRemoveContainer(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset, PRUint32 aNodeOrigLen)
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
|
||||
if (!aNode || !aParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (item->startNode.get() == aNode)
|
||||
{
|
||||
item->startNode = aParent;
|
||||
item->startOffset += aOffset;
|
||||
}
|
||||
if (item->endNode.get() == aNode)
|
||||
{
|
||||
item->endNode = aParent;
|
||||
item->endOffset += aOffset;
|
||||
}
|
||||
if ((item->startNode.get() == aParent) && (item->startOffset > aOffset))
|
||||
item->startOffset += (PRInt32)aNodeOrigLen-1;
|
||||
if ((item->endNode.get() == aParent) && (item->endOffset > aOffset))
|
||||
item->endOffset += (PRInt32)aNodeOrigLen-1;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillInsertContainer()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidInsertContainer()
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillMoveNode()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidMoveNode(nsIDOMNode *aOldParent, PRInt32 aOldOffset, nsIDOMNode *aNewParent, PRInt32 aNewOffset)
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
|
||||
if (!aOldParent || !aNewParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// like a delete in aOldParent
|
||||
if ((item->startNode.get() == aOldParent) && (item->startOffset > aOldOffset))
|
||||
item->startOffset--;
|
||||
if ((item->endNode.get() == aOldParent) && (item->endOffset > aOldOffset))
|
||||
item->endOffset--;
|
||||
|
||||
// and like an insert in aNewParent
|
||||
if ((item->startNode.get() == aNewParent) && (item->startOffset > aNewOffset))
|
||||
item->startOffset++;
|
||||
if ((item->endNode.get() == aNewParent) && (item->endOffset > aNewOffset))
|
||||
item->endOffset++;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* helper class for nsSelectionState. nsRangeStore stores range endpoints.
|
||||
*/
|
||||
|
||||
// DEBUG: PRInt32 nsRangeStore::n = 0;
|
||||
|
||||
nsRangeStore::nsRangeStore()
|
||||
{
|
||||
// DEBUG: n++; printf("range store alloc count=%d\n", n);
|
||||
}
|
||||
nsRangeStore::~nsRangeStore()
|
||||
{
|
||||
// DEBUG: n--; printf("range store alloc count=%d\n", n);
|
||||
}
|
||||
|
||||
nsresult nsRangeStore::StoreRange(nsIDOMRange *aRange)
|
||||
{
|
||||
if (!aRange) return NS_ERROR_NULL_POINTER;
|
||||
aRange->GetStartContainer(getter_AddRefs(startNode));
|
||||
aRange->GetEndContainer(getter_AddRefs(endNode));
|
||||
aRange->GetStartOffset(&startOffset);
|
||||
aRange->GetEndOffset(&endOffset);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsRangeStore::GetRange(nsCOMPtr<nsIDOMRange> *outRange)
|
||||
{
|
||||
if (!outRange) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = nsComponentManager::CreateInstance(kCRangeCID,
|
||||
nsnull,
|
||||
NS_GET_IID(nsIDOMRange),
|
||||
getter_AddRefs(*outRange));
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
res = (*outRange)->SetStart(startNode, startOffset);
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
res = (*outRange)->SetEnd(endNode, endOffset);
|
||||
return res;
|
||||
}
|
245
editor/base/nsSelectionState.h
Normal file
245
editor/base/nsSelectionState.h
Normal file
@ -0,0 +1,245 @@
|
||||
/* -*- 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.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#ifndef __selectionstate_h__
|
||||
#define __selectionstate_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsIDOMNode.h"
|
||||
|
||||
class nsIDOMCharacterData;
|
||||
class nsIDOMRange;
|
||||
class nsISelection;
|
||||
|
||||
/***************************************************************************
|
||||
* class for recording selection info. stores selection as collection of
|
||||
* { {startnode, startoffset} , {endnode, endoffset} } tuples. Cant store
|
||||
* ranges since dom gravity will possibly change the ranges.
|
||||
*/
|
||||
|
||||
// first a helper struct for saving/setting ranges
|
||||
struct nsRangeStore
|
||||
{
|
||||
nsRangeStore();
|
||||
~nsRangeStore();
|
||||
nsresult StoreRange(nsIDOMRange *aRange);
|
||||
nsresult GetRange(nsCOMPtr<nsIDOMRange> *outRange);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> startNode;
|
||||
PRInt32 startOffset;
|
||||
nsCOMPtr<nsIDOMNode> endNode;
|
||||
PRInt32 endOffset;
|
||||
// DEBUG: static PRInt32 n;
|
||||
};
|
||||
|
||||
class nsSelectionState
|
||||
{
|
||||
public:
|
||||
|
||||
nsSelectionState();
|
||||
~nsSelectionState();
|
||||
|
||||
nsresult SaveSelection(nsISelection *aSel);
|
||||
nsresult RestoreSelection(nsISelection *aSel);
|
||||
PRBool IsCollapsed();
|
||||
PRBool IsEqual(nsSelectionState *aSelState);
|
||||
void MakeEmpty();
|
||||
PRBool IsEmpty();
|
||||
protected:
|
||||
nsVoidArray mArray;
|
||||
|
||||
friend class nsRangeUpdater;
|
||||
};
|
||||
|
||||
class nsRangeUpdater
|
||||
{
|
||||
public:
|
||||
|
||||
nsRangeUpdater();
|
||||
~nsRangeUpdater();
|
||||
|
||||
void* RegisterRange(nsIDOMRange *aRange);
|
||||
nsCOMPtr<nsIDOMRange> ReclaimRange(void *aCookie);
|
||||
void DropRange(void *aCookie);
|
||||
void RegisterRangeItem(nsRangeStore *aRangeItem);
|
||||
void DropRangeItem(nsRangeStore *aRangeItem);
|
||||
nsresult RegisterSelectionState(nsSelectionState &aSelState);
|
||||
nsresult DropSelectionState(nsSelectionState &aSelState);
|
||||
|
||||
// editor selection gravity routines. Note that we can't always depend on
|
||||
// DOM Range gravity to do what we want to the "real" selection. For instance,
|
||||
// if you move a node, that corresponds to deleting it and reinserting it.
|
||||
// DOM Range gravity will promote the selection out of the node on deletion,
|
||||
// which is not what you want if you know you are reinserting it.
|
||||
nsresult SelAdjCreateNode(nsIDOMNode *aParent, PRInt32 aPosition);
|
||||
nsresult SelAdjInsertNode(nsIDOMNode *aParent, PRInt32 aPosition);
|
||||
nsresult SelAdjDeleteNode(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset);
|
||||
nsresult SelAdjSplitNode(nsIDOMNode *aOldRightNode, PRInt32 aOffset, nsIDOMNode *aNewLeftNode);
|
||||
nsresult SelAdjJoinNodes(nsIDOMNode *aLeftNode,
|
||||
nsIDOMNode *aRightNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aOffset,
|
||||
PRInt32 aOldLeftNodeLength);
|
||||
nsresult SelAdjInsertText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, const nsString &aString);
|
||||
nsresult SelAdjDeleteText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, PRInt32 aLength);
|
||||
// the following gravity routines need will/did sandwiches, because the other gravity
|
||||
// routines will be called inside of these sandwiches, but should be ignored.
|
||||
nsresult WillReplaceContainer();
|
||||
nsresult DidReplaceContainer(nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode);
|
||||
nsresult WillRemoveContainer();
|
||||
nsresult DidRemoveContainer(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset, PRUint32 aNodeOrigLen);
|
||||
nsresult WillInsertContainer();
|
||||
nsresult DidInsertContainer();
|
||||
nsresult WillMoveNode();
|
||||
nsresult DidMoveNode(nsIDOMNode *aOldParent, PRInt32 aOldOffset, nsIDOMNode *aNewParent, PRInt32 aNewOffset);
|
||||
protected:
|
||||
nsVoidArray mArray;
|
||||
PRBool mLock;
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidReplaceContainer()
|
||||
*/
|
||||
|
||||
class nsAutoReplaceContainerSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
nsIDOMNode *mOriginalNode;
|
||||
nsIDOMNode *mNewNode;
|
||||
|
||||
public:
|
||||
nsAutoReplaceContainerSelNotify(nsRangeUpdater &aRangeUpdater, nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode) :
|
||||
mRU(aRangeUpdater)
|
||||
,mOriginalNode(aOriginalNode)
|
||||
,mNewNode(aNewNode)
|
||||
{
|
||||
mRU.WillReplaceContainer();
|
||||
}
|
||||
|
||||
~nsAutoReplaceContainerSelNotify()
|
||||
{
|
||||
mRU.DidReplaceContainer(mOriginalNode, mNewNode);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidRemoveContainer()
|
||||
*/
|
||||
|
||||
class nsAutoRemoveContainerSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
nsIDOMNode *mNode;
|
||||
nsIDOMNode *mParent;
|
||||
PRInt32 mOffset;
|
||||
PRUint32 mNodeOrigLen;
|
||||
|
||||
public:
|
||||
nsAutoRemoveContainerSelNotify(nsRangeUpdater &aRangeUpdater,
|
||||
nsIDOMNode *aNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aOffset,
|
||||
PRUint32 aNodeOrigLen) :
|
||||
mRU(aRangeUpdater)
|
||||
,mNode(aNode)
|
||||
,mParent(aParent)
|
||||
,mOffset(aOffset)
|
||||
,mNodeOrigLen(aNodeOrigLen)
|
||||
{
|
||||
mRU.WillRemoveContainer();
|
||||
}
|
||||
|
||||
~nsAutoRemoveContainerSelNotify()
|
||||
{
|
||||
mRU.DidRemoveContainer(mNode, mParent, mOffset, mNodeOrigLen);
|
||||
}
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidInsertContainer()
|
||||
*/
|
||||
|
||||
class nsAutoInsertContainerSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
|
||||
public:
|
||||
nsAutoInsertContainerSelNotify(nsRangeUpdater &aRangeUpdater) :
|
||||
mRU(aRangeUpdater)
|
||||
{
|
||||
mRU.WillInsertContainer();
|
||||
}
|
||||
|
||||
~nsAutoInsertContainerSelNotify()
|
||||
{
|
||||
mRU.DidInsertContainer();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidMoveNode()
|
||||
*/
|
||||
|
||||
class nsAutoMoveNodeSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
nsIDOMNode *mOldParent;
|
||||
nsIDOMNode *mNewParent;
|
||||
PRInt32 mOldOffset;
|
||||
PRInt32 mNewOffset;
|
||||
|
||||
public:
|
||||
nsAutoMoveNodeSelNotify(nsRangeUpdater &aRangeUpdater,
|
||||
nsIDOMNode *aOldParent,
|
||||
PRInt32 aOldOffset,
|
||||
nsIDOMNode *aNewParent,
|
||||
PRInt32 aNewOffset) :
|
||||
mRU(aRangeUpdater)
|
||||
,mOldParent(aOldParent)
|
||||
,mNewParent(aNewParent)
|
||||
,mOldOffset(aOldOffset)
|
||||
,mNewOffset(aNewOffset)
|
||||
{
|
||||
mRU.WillMoveNode();
|
||||
}
|
||||
|
||||
~nsAutoMoveNodeSelNotify()
|
||||
{
|
||||
mRU.DidMoveNode(mOldParent, mOldOffset, mNewParent, mNewOffset);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -48,7 +48,7 @@ static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
|
||||
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
|
||||
|
||||
#define CANCEL_OPERATION_IF_READONLY_OR_DISABLED \
|
||||
if ((mFlags & nsIHTMLEditor::eEditorReadonlyMask) || (mFlags & nsIHTMLEditor::eEditorDisabledMask)) \
|
||||
if ((mFlags & nsIPlaintextEditor::eEditorReadonlyMask) || (mFlags & nsIPlaintextEditor::eEditorDisabledMask)) \
|
||||
{ \
|
||||
*aCancel = PR_TRUE; \
|
||||
return NS_OK; \
|
||||
@ -101,7 +101,7 @@ NS_IMPL_QUERY_INTERFACE1(nsTextEditRules, nsIEditRules)
|
||||
********************************************************/
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTextEditRules::Init(nsHTMLEditor *aEditor, PRUint32 aFlags)
|
||||
nsTextEditRules::Init(nsPlaintextEditor *aEditor, PRUint32 aFlags)
|
||||
{
|
||||
if (!aEditor) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
@ -125,10 +125,8 @@ nsTextEditRules::Init(nsHTMLEditor *aEditor, PRUint32 aFlags)
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// create a range that is the entire body contents
|
||||
nsCOMPtr<nsIDOMRange> wholeDoc;
|
||||
res = nsComponentManager::CreateInstance(kRangeCID, nsnull, NS_GET_IID(nsIDOMRange),
|
||||
getter_AddRefs(wholeDoc));
|
||||
if (NS_FAILED(res)) return res;
|
||||
nsCOMPtr<nsIDOMRange> wholeDoc = do_CreateInstance(kRangeCID);
|
||||
if (!wholeDoc) return NS_ERROR_NULL_POINTER;
|
||||
wholeDoc->SetStart(mBody,0);
|
||||
nsCOMPtr<nsIDOMNodeList> list;
|
||||
res = mBody->GetChildNodes(getter_AddRefs(list));
|
||||
@ -163,11 +161,9 @@ nsTextEditRules::SetFlags(PRUint32 aFlags)
|
||||
// SetFlags() is really meant to only be called once
|
||||
// and at editor init time.
|
||||
|
||||
PRBool willBePlaintext = (aFlags & nsIHTMLEditor::eEditorPlaintextMask) != 0;
|
||||
PRBool alreadyPlaintext = (mFlags & nsIHTMLEditor::eEditorPlaintextMask) != 0;
|
||||
|
||||
PRBool willBePlaintext = (aFlags & nsIPlaintextEditor::eEditorPlaintextMask) != 0;
|
||||
PRBool alreadyPlaintext = (mFlags & nsIPlaintextEditor::eEditorPlaintextMask) != 0;
|
||||
mFlags = aFlags;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -207,8 +203,6 @@ nsTextEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
||||
res = CreateBogusNodeIfNeeded(selection);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// create moz-br and adjust selection if needed
|
||||
res = AdjustSelection(selection, aDirection);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@ -340,42 +334,7 @@ nsTextEditRules::WillInsert(nsISelection *aSelection, PRBool *aCancel)
|
||||
mBogusNode = do_QueryInterface(nsnull);
|
||||
}
|
||||
|
||||
// this next only works for collapsed selections right now,
|
||||
// because selection is a pain to work with when not collapsed.
|
||||
// (no good way to extend start or end of selection)
|
||||
PRBool bCollapsed;
|
||||
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!bCollapsed) return NS_OK;
|
||||
|
||||
// if we are after a mozBR in the same block, then move selection
|
||||
// to be before it
|
||||
nsCOMPtr<nsIDOMNode> selNode, priorNode;
|
||||
PRInt32 selOffset;
|
||||
// get the (collapsed) selection location
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// get prior node
|
||||
res = mEditor->GetPriorHTMLNode(selNode, selOffset, address_of(priorNode));
|
||||
if (NS_SUCCEEDED(res) && priorNode && nsHTMLEditUtils::IsMozBR(priorNode))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> block1, block2;
|
||||
if (mEditor->IsBlockNode(selNode)) block1 = selNode;
|
||||
else block1 = mEditor->GetBlockNodeParent(selNode);
|
||||
block2 = mEditor->GetBlockNodeParent(priorNode);
|
||||
|
||||
if (block1 != block2) return NS_OK;
|
||||
|
||||
// if we are here then the selection is right after a mozBR
|
||||
// that is in the same block as the selection. We need to move
|
||||
// the selection start to be before the mozBR.
|
||||
res = nsEditor::GetNodeLocation(priorNode, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = aSelection->Collapse(selNode,selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
return res;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -384,44 +343,13 @@ nsTextEditRules::DidInsert(nsISelection *aSelection, nsresult aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::GetTopEnclosingPre(nsIDOMNode *aNode,
|
||||
nsIDOMNode** aOutPreNode)
|
||||
{
|
||||
// check parms
|
||||
if (!aNode || !aOutPreNode)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
*aOutPreNode = 0;
|
||||
|
||||
nsresult res = NS_OK;
|
||||
nsCOMPtr<nsIDOMNode> node, parentNode;
|
||||
node = do_QueryInterface(aNode);
|
||||
|
||||
while (node)
|
||||
{
|
||||
nsAutoString tag;
|
||||
nsEditor::GetTagString(node, tag);
|
||||
if (tag.EqualsWithConversion("pre", PR_TRUE))
|
||||
*aOutPreNode = node;
|
||||
else if (tag.EqualsWithConversion("body", PR_TRUE))
|
||||
break;
|
||||
|
||||
res = node->GetParentNode(getter_AddRefs(parentNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
node = parentNode;
|
||||
}
|
||||
|
||||
NS_IF_ADDREF(*aOutPreNode);
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled)
|
||||
{
|
||||
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
||||
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
|
||||
*aHandled = PR_FALSE;
|
||||
if (mFlags & nsIHTMLEditor::eEditorSingleLineMask) {
|
||||
if (mFlags & nsIPlaintextEditor::eEditorSingleLineMask) {
|
||||
*aCancel = PR_TRUE;
|
||||
}
|
||||
else
|
||||
@ -444,72 +372,6 @@ nsTextEditRules::WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBo
|
||||
// we want to ignore result of WillInsert()
|
||||
*aCancel = PR_FALSE;
|
||||
|
||||
// Mail rule: split any <pre> tags in the way,
|
||||
// since they're probably quoted text.
|
||||
// For now, do this for all plaintext since mail is our main customer
|
||||
// and we don't currently set eEditorMailMask for plaintext mail.
|
||||
if (mTheAction != nsHTMLEditor::kOpInsertQuotation) // && mFlags & nsIHTMLEditor::eEditorMailMask)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> preNode, selNode;
|
||||
PRInt32 selOffset, newOffset;
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// If any of the following fail, then just proceed with the
|
||||
// normal break insertion without worrying about the error
|
||||
res = GetTopEnclosingPre(selNode, getter_AddRefs(preNode));
|
||||
if (NS_SUCCEEDED(res) && preNode)
|
||||
{
|
||||
// Only split quote nodes: see if it has the attribute _moz_quote
|
||||
nsCOMPtr<nsIDOMElement> preElement (do_QueryInterface(preNode));
|
||||
if (preElement)
|
||||
{
|
||||
nsString mozQuote; mozQuote.AssignWithConversion("_moz_quote");
|
||||
nsString mozQuoteVal;
|
||||
PRBool isMozQuote = PR_FALSE;
|
||||
if (NS_SUCCEEDED(mEditor->GetAttributeValue(preElement, mozQuote,
|
||||
mozQuoteVal, isMozQuote))
|
||||
&& isMozQuote)
|
||||
{
|
||||
printf("It's a moz quote -- splitting\n");
|
||||
nsCOMPtr<nsIDOMNode> outLeftNode;
|
||||
nsCOMPtr<nsIDOMNode> outRightNode;
|
||||
res = mEditor->SplitNodeDeep(preNode, selNode, selOffset, &newOffset, PR_TRUE, address_of(outLeftNode), address_of(outRightNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
PRBool bIsEmptyNode;
|
||||
|
||||
// rememeber parent of selNode now, since we might delete selNode below
|
||||
res = preNode->GetParentNode(getter_AddRefs(selNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
if (outLeftNode)
|
||||
{
|
||||
res = mEditor->IsEmptyNode(outLeftNode, &bIsEmptyNode, PR_TRUE, PR_FALSE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (bIsEmptyNode) mEditor->DeleteNode(outLeftNode);
|
||||
}
|
||||
if (outRightNode)
|
||||
{
|
||||
// HACK alert: consume a br if there is one at front of node
|
||||
nsCOMPtr<nsIDOMNode> firstNode;
|
||||
res = mEditor->GetFirstEditableNode(outRightNode, address_of(firstNode));
|
||||
if (firstNode && nsHTMLEditUtils::IsBreak(firstNode))
|
||||
{
|
||||
mEditor->DeleteNode(firstNode);
|
||||
}
|
||||
|
||||
res = mEditor->IsEmptyNode(outRightNode, &bIsEmptyNode, PR_TRUE, PR_FALSE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (bIsEmptyNode) mEditor->DeleteNode(outRightNode);
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
// last ePrevious param causes selection to be set before the break
|
||||
res = mEditor->CreateBR(selNode, newOffset, address_of(brNode), nsIEditor::ePrevious);
|
||||
*aHandled = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -519,42 +381,44 @@ nsTextEditRules::DidInsertBreak(nsISelection *aSelection, nsresult aResult)
|
||||
{
|
||||
// we only need to execute the stuff below if we are a plaintext editor.
|
||||
// html editors have a different mechanism for putting in mozBR's
|
||||
// (because there are a bunch more placesyou have to worry about it in html)
|
||||
if (!nsIHTMLEditor::eEditorPlaintextMask & mFlags) return NS_OK;
|
||||
// (because there are a bunch more places you have to worry about it in html)
|
||||
if (!nsIPlaintextEditor::eEditorPlaintextMask & mFlags) return NS_OK;
|
||||
|
||||
// if we are at the end of the document, we need to insert
|
||||
// a special mozBR following the normal br, and then set the
|
||||
// selection to stick to the mozBR.
|
||||
PRInt32 selOffset;
|
||||
nsCOMPtr<nsIDOMNode> nearNode, selNode;
|
||||
nsCOMPtr<nsIDOMNode> nearNode, selNode, root, temp;
|
||||
nsCOMPtr<nsIDOMElement> rootElem;
|
||||
nsresult res;
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->GetPriorHTMLNode(selNode, selOffset, address_of(nearNode));
|
||||
// confirm we are at end of document
|
||||
if (selOffset == 0) return NS_OK; // cant be after a br if we are at offset 0
|
||||
res = mEditor->GetRootElement(getter_AddRefs(rootElem));
|
||||
if (NS_FAILED(res)) return res;
|
||||
root = do_QueryInterface(rootElem);
|
||||
if (!root) return NS_ERROR_NULL_POINTER;
|
||||
if (selNode != root) return NS_OK; // must be inside text node or somewhere other than end of root
|
||||
temp = mEditor->GetChildAt(selNode, selOffset);
|
||||
if (temp) return NS_OK; // cant be at end of there is a node after us.
|
||||
nearNode = mEditor->GetChildAt(selNode, selOffset-1);
|
||||
if (nearNode && nsHTMLEditUtils::IsBreak(nearNode) && !nsHTMLEditUtils::IsMozBR(nearNode))
|
||||
{
|
||||
PRBool bIsLast;
|
||||
res = mEditor->IsLastEditableChild(nearNode, &bIsLast);
|
||||
nsCOMPtr<nsISelection> sel(aSelection);
|
||||
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(sel));
|
||||
// need to insert special moz BR. Why? Because if we don't
|
||||
// the user will see no new line for the break. Also, things
|
||||
// like table cells won't grow in height.
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
res = CreateMozBR(selNode, selOffset, address_of(brNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = nsEditor::GetNodeLocation(brNode, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
selPrivate->SetInterlinePosition(PR_TRUE);
|
||||
res = aSelection->Collapse(selNode,selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (bIsLast)
|
||||
{
|
||||
nsCOMPtr<nsISelection> sel(aSelection);
|
||||
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(sel));
|
||||
// need to insert special moz BR. Why? Because if we don't
|
||||
// the user will see no new line for the break. Also, things
|
||||
// like table cells won't grow in height.
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
res = CreateMozBR(selNode, selOffset, address_of(brNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = nsEditor::GetNodeLocation(brNode, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
selPrivate->SetInterlinePosition(PR_TRUE);
|
||||
res = aSelection->Collapse(selNode,selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
// mEditor->DumpContentTree();
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -595,7 +459,7 @@ nsTextEditRules::WillInsertText(PRInt32 aAction,
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// handle password field docs
|
||||
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
||||
if (mFlags & nsIPlaintextEditor::eEditorPasswordMask)
|
||||
{
|
||||
res = mEditor->GetTextSelectionOffsets(aSelection, start, end);
|
||||
NS_ASSERTION((NS_SUCCEEDED(res)), "getTextSelectionOffsets failed!");
|
||||
@ -621,7 +485,7 @@ nsTextEditRules::WillInsertText(PRInt32 aAction,
|
||||
// handle password field data
|
||||
// this has the side effect of changing all the characters in aOutString
|
||||
// to the replacement character
|
||||
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
||||
if (mFlags & nsIPlaintextEditor::eEditorPasswordMask)
|
||||
{
|
||||
res = EchoInsertionToPWBuff(start, end, outString);
|
||||
if (NS_FAILED(res)) return res;
|
||||
@ -646,7 +510,7 @@ nsTextEditRules::WillInsertText(PRInt32 aAction,
|
||||
rv = prefs->GetIntPref("editor.singleLine.pasteNewlines",
|
||||
&singleLineNewlineBehavior);
|
||||
|
||||
if (nsIHTMLEditor::eEditorSingleLineMask & mFlags)
|
||||
if (nsIPlaintextEditor::eEditorSingleLineMask & mFlags)
|
||||
{
|
||||
if (singleLineNewlineBehavior == eReplaceWithSpaces)
|
||||
outString->ReplaceChar(CRLF, ' ');
|
||||
@ -731,7 +595,7 @@ nsTextEditRules::WillInsertText(PRInt32 aAction,
|
||||
// is it a return?
|
||||
if (subStr.EqualsWithConversion("\n"))
|
||||
{
|
||||
if (nsIHTMLEditor::eEditorSingleLineMask & mFlags)
|
||||
if (nsIPlaintextEditor::eEditorSingleLineMask & mFlags)
|
||||
{
|
||||
NS_ASSERTION((singleLineNewlineBehavior == ePasteIntact),
|
||||
"Newline improperly getting into single-line edit field!");
|
||||
@ -814,7 +678,7 @@ nsTextEditRules::WillSetTextProperty(nsISelection *aSelection, PRBool *aCancel,
|
||||
nsresult res = NS_OK;
|
||||
|
||||
// XXX: should probably return a success value other than NS_OK that means "not allowed"
|
||||
if (nsIHTMLEditor::eEditorPlaintextMask & mFlags) {
|
||||
if (nsIPlaintextEditor::eEditorPlaintextMask & mFlags) {
|
||||
*aCancel = PR_TRUE;
|
||||
}
|
||||
return res;
|
||||
@ -834,7 +698,7 @@ nsTextEditRules::WillRemoveTextProperty(nsISelection *aSelection, PRBool *aCance
|
||||
nsresult res = NS_OK;
|
||||
|
||||
// XXX: should probably return a success value other than NS_OK that means "not allowed"
|
||||
if (nsIHTMLEditor::eEditorPlaintextMask & mFlags) {
|
||||
if (nsIPlaintextEditor::eEditorPlaintextMask & mFlags) {
|
||||
*aCancel = PR_TRUE;
|
||||
}
|
||||
return res;
|
||||
@ -864,7 +728,7 @@ nsTextEditRules::WillDeleteSelection(nsISelection *aSelection,
|
||||
*aCancel = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
||||
if (mFlags & nsIPlaintextEditor::eEditorPasswordMask)
|
||||
{
|
||||
// manage the password buffer
|
||||
PRInt32 start, end;
|
||||
@ -1098,7 +962,7 @@ nsTextEditRules::WillOutputText(nsISelection *aSelection,
|
||||
|
||||
if (PR_TRUE == aOutputFormat->EqualsWithConversion("text/plain"))
|
||||
{ // only use these rules for plain text output
|
||||
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
||||
if (mFlags & nsIPlaintextEditor::eEditorPasswordMask)
|
||||
{
|
||||
*aOutString = mPasswordText;
|
||||
*aHandled = PR_TRUE;
|
||||
@ -1288,7 +1152,7 @@ nsTextEditRules::TruncateInsertionIfNeeded(nsISelection *aSelection,
|
||||
nsresult res = NS_OK;
|
||||
*aOutString = *aInString;
|
||||
|
||||
if ((-1 != aMaxLength) && (mFlags & nsIHTMLEditor::eEditorPlaintextMask))
|
||||
if ((-1 != aMaxLength) && (mFlags & nsIPlaintextEditor::eEditorPlaintextMask))
|
||||
{
|
||||
// Get the current text length.
|
||||
// Get the length of inString.
|
||||
@ -1388,69 +1252,3 @@ nsTextEditRules::DeleteEmptyTextNode(nsIDOMNode *aNode)
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection aDirection)
|
||||
{
|
||||
if (!aSelection) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// if the selection isn't collapsed, do nothing.
|
||||
PRBool bCollapsed;
|
||||
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!bCollapsed) return res;
|
||||
|
||||
// get the (collapsed) selection location
|
||||
nsCOMPtr<nsIDOMNode> selNode, temp;
|
||||
PRInt32 selOffset;
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
temp = selNode;
|
||||
|
||||
// are we in an editable node?
|
||||
while (!mEditor->IsEditable(selNode))
|
||||
{
|
||||
// scan up the tree until we find an editable place to be
|
||||
res = nsEditor::GetNodeLocation(temp, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!selNode) return NS_ERROR_FAILURE;
|
||||
temp = selNode;
|
||||
}
|
||||
|
||||
// are we in a text node?
|
||||
nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(selNode);
|
||||
if (textNode)
|
||||
return NS_OK; // we LIKE it when we are in a text node. that RULZ
|
||||
|
||||
// do we need to insert a special mozBR? We do if we are:
|
||||
// 1) after a block element AND
|
||||
// 2) at the end of the body OR before another block
|
||||
|
||||
nsCOMPtr<nsIDOMNode> priorNode, nextNode;
|
||||
res = mEditor->GetPriorHTMLSibling(selNode, selOffset, address_of(priorNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->GetNextHTMLSibling(selNode, selOffset, address_of(nextNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// is priorNode a block?
|
||||
if (priorNode && mEditor->IsBlockNode(priorNode))
|
||||
{
|
||||
if (!nextNode || mEditor->IsBlockNode(nextNode))
|
||||
{
|
||||
nsCOMPtr<nsISelection> sel(aSelection);
|
||||
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(sel));
|
||||
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
res = CreateMozBR(selNode, selOffset, address_of(brNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = nsEditor::GetNodeLocation(brNode, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// selection stays *before* moz-br, sticking to it
|
||||
selPrivate->SetInterlinePosition(PR_TRUE);
|
||||
res = aSelection->Collapse(selNode,selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "nsHTMLEditor.h"
|
||||
#include "nsPlaintextEditor.h"
|
||||
#include "nsIDOMNode.h"
|
||||
|
||||
#include "nsEditRules.h"
|
||||
@ -50,7 +50,7 @@ public:
|
||||
virtual ~nsTextEditRules();
|
||||
|
||||
// nsIEditRules methods
|
||||
NS_IMETHOD Init(nsHTMLEditor *aEditor, PRUint32 aFlags);
|
||||
NS_IMETHOD Init(nsPlaintextEditor *aEditor, PRUint32 aFlags);
|
||||
NS_IMETHOD BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection);
|
||||
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection);
|
||||
NS_IMETHOD WillDoAction(nsISelection *aSelection, nsRulesInfo *aInfo, PRBool *aCancel, PRBool *aHandled);
|
||||
@ -163,17 +163,15 @@ protected:
|
||||
|
||||
PRBool DeleteEmptyTextNode(nsIDOMNode *aNode);
|
||||
|
||||
nsresult AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection aDirection);
|
||||
|
||||
// data members
|
||||
nsHTMLEditor *mEditor; // note that we do not refcount the editor
|
||||
nsString mPasswordText; // a buffer we use to store the real value of password editors
|
||||
nsCOMPtr<nsIDOMNode> mBogusNode; // magic node acts as placeholder in empty doc
|
||||
nsCOMPtr<nsIDOMNode> mBody; // cached root node
|
||||
PRUint32 mFlags;
|
||||
PRUint32 mActionNesting;
|
||||
PRBool mLockRulesSniffing;
|
||||
PRInt32 mTheAction; // the top level editor action
|
||||
nsPlaintextEditor *mEditor; // note that we do not refcount the editor
|
||||
nsString mPasswordText; // a buffer we use to store the real value of password editors
|
||||
nsCOMPtr<nsIDOMNode> mBogusNode; // magic node acts as placeholder in empty doc
|
||||
nsCOMPtr<nsIDOMNode> mBody; // cached root node
|
||||
PRUint32 mFlags;
|
||||
PRUint32 mActionNesting;
|
||||
PRBool mLockRulesSniffing;
|
||||
PRInt32 mTheAction; // the top level editor action
|
||||
// friends
|
||||
friend class nsAutoLockRulesSniffing;
|
||||
|
||||
|
58
editor/base/nsTextEditorReg.cpp
Normal file
58
editor/base/nsTextEditorReg.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
/* -*- 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.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#include "nsIGenericFactory.h"
|
||||
|
||||
#include "nsEditorCID.h"
|
||||
#include "nsEditor.h" // for gInstanceCount
|
||||
#include "nsPlaintextEditor.h"
|
||||
#include "nsEditorService.h"
|
||||
#include "nsEditorController.h" //CID
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Define the contructor function for the objects
|
||||
//
|
||||
// NOTE: This creates an instance of objects by using the default constructor
|
||||
//
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorController)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorService)
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsPlaintextEditor)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Define a table of CIDs implemented by this module along with other
|
||||
// information like the function to create an instance, contractid, and
|
||||
// class name.
|
||||
//
|
||||
static nsModuleComponentInfo components[] = {
|
||||
{ "Text Editor", NS_TEXTEDITOR_CID,
|
||||
"@mozilla.org/editor/texteditor;1", nsPlaintextEditorConstructor, },
|
||||
{ "Editor Controller", NS_EDITORCONTROLLER_CID,
|
||||
"@mozilla.org/editor/editorcontroller;1", nsEditorControllerConstructor, }
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implement the NSGetModule() exported function for your module
|
||||
// and the entire implementation of the module object.
|
||||
//
|
||||
NS_IMPL_NSGETMODULE("nsEditorModule", components)
|
@ -910,7 +910,7 @@ nsEditorShell::InstantiateEditor(nsIDOMDocument *aDoc, nsIPresShell *aPresShell)
|
||||
{
|
||||
if (mEditorTypeString.EqualsWithConversion("text"))
|
||||
{
|
||||
err = editor->Init(aDoc, aPresShell, nsnull, selCon, nsIHTMLEditor::eEditorPlaintextMask | nsIHTMLEditor::eEditorEnableWrapHackMask);
|
||||
err = editor->Init(aDoc, aPresShell, nsnull, selCon, nsIPlaintextEditor::eEditorPlaintextMask | nsIPlaintextEditor::eEditorEnableWrapHackMask);
|
||||
mEditorType = ePlainTextEditorType;
|
||||
}
|
||||
else if (mEditorTypeString.EqualsWithConversion("html") || mEditorTypeString.IsEmpty()) // empty string default to HTML editor
|
||||
@ -920,7 +920,7 @@ nsEditorShell::InstantiateEditor(nsIDOMDocument *aDoc, nsIPresShell *aPresShell)
|
||||
}
|
||||
else if (mEditorTypeString.EqualsWithConversion("htmlmail")) // HTML editor with special mail rules
|
||||
{
|
||||
err = editor->Init(aDoc, aPresShell, nsnull, selCon, nsIHTMLEditor::eEditorMailMask);
|
||||
err = editor->Init(aDoc, aPresShell, nsnull, selCon, nsIPlaintextEditor::eEditorMailMask);
|
||||
mEditorType = eHTMLTextEditorType;
|
||||
}
|
||||
else
|
||||
@ -3423,7 +3423,7 @@ nsEditorShell::GetDocumentEditable(PRBool *aDocumentEditable)
|
||||
PRUint32 editorFlags;
|
||||
editor->GetFlags(&editorFlags);
|
||||
|
||||
if (editorFlags & nsIHTMLEditor::eEditorReadonlyMask)
|
||||
if (editorFlags & nsIPlaintextEditor::eEditorReadonlyMask)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> doc;
|
||||
|
@ -31,6 +31,32 @@
|
||||
[scriptable, uuid(b5f39ed4-1dd1-11b2-9d00-fd54d6f54962)]
|
||||
interface nsIPlaintextEditor : nsISupports
|
||||
{
|
||||
|
||||
/* the bits in an editor behavior mask. */
|
||||
const short eEditorPlaintextBit = 0; /* only plain text entry is allowed via events */
|
||||
const short eEditorSingleLineBit = 1; /* enter key and CR-LF handled specially */
|
||||
const short eEditorPasswordBit = 2; /* text is not entered into content, only a representative character */
|
||||
const short eEditorReadonlyBit = 3; /* editing events are disabled. Editor may still accept focus. */
|
||||
const short eEditorDisabledBit = 4; /* all events are disabled (like scrolling). Editor will not accept focus. */
|
||||
const short eEditorFilterInputBit = 5; /* text input is limited to certain character types, use mFilter */
|
||||
const short eEditorMailBit = 6; /* use mail-compose editting rules */
|
||||
const short eEditorDisableForcedUpdatesBit = 7; /* prevent immediate view refreshes */
|
||||
const short eEditorDisableForcedReflowsBit = 8; /* prevent immediate reflows */
|
||||
const short eEditorEnableWrapHackBit = 9; /* allow the editor to set font: monospace on the root node */
|
||||
const short eEditorWidgetBit = 10; /* bit for widgets */
|
||||
|
||||
const long eEditorPlaintextMask = 1;
|
||||
const long eEditorSingleLineMask = 2;
|
||||
const long eEditorPasswordMask = 4;
|
||||
const long eEditorReadonlyMask = 8;
|
||||
const long eEditorDisabledMask = 16;
|
||||
const long eEditorFilterInputMask = 32;
|
||||
const long eEditorMailMask = 64;
|
||||
const long eEditorDisableForcedUpdatesMask = 128;
|
||||
const long eEditorDisableForcedReflowsMask = 256;
|
||||
const long eEditorEnableWrapHackMask = 512;
|
||||
const long eEditorWidgetMask = 1024;
|
||||
|
||||
/**
|
||||
* The length of the contents in characters.
|
||||
*/
|
||||
|
@ -28,7 +28,7 @@
|
||||
0xa6cf911d, 0x15b3, 0x11d2, \
|
||||
{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} }
|
||||
|
||||
class nsHTMLEditor;
|
||||
class nsPlaintextEditor;
|
||||
class nsISelection;
|
||||
|
||||
/***************************************************************************
|
||||
@ -57,7 +57,7 @@ public:
|
||||
//Interfaces for addref and release and queryinterface
|
||||
//NOTE: Use NS_DECL_ISUPPORTS_INHERITED in any class inherited from nsIEditRules
|
||||
|
||||
NS_IMETHOD Init(nsHTMLEditor *aEditor, PRUint32 aFlags)=0;
|
||||
NS_IMETHOD Init(nsPlaintextEditor *aEditor, PRUint32 aFlags)=0;
|
||||
NS_IMETHOD BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection)=0;
|
||||
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)=0;
|
||||
NS_IMETHOD WillDoAction(nsISelection *aSelection, nsRulesInfo *aInfo, PRBool *aCancel, PRBool *aHandled)=0;
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include "nsIKBStateControl.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsIScrollbar.h"
|
||||
#include "nsIPlaintextEditor.h"
|
||||
|
||||
#include "nsIFrame.h" // Needed by IME code
|
||||
|
||||
@ -93,7 +94,7 @@
|
||||
#include "JoinElementTxn.h"
|
||||
#include "nsStyleSheetTxns.h"
|
||||
#include "IMETextTxn.h"
|
||||
#include "nsIHTMLEditor.h"
|
||||
|
||||
// included for nsEditor::CreateHTMLContent
|
||||
#include "nsIElementFactory.h"
|
||||
#include "nsINodeInfo.h"
|
||||
@ -148,738 +149,6 @@ const PRUnichar nbsp = 160;
|
||||
PRInt32 nsEditor::gInstanceCount = 0;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* class for recording selection info. stores selection as collection of
|
||||
* { {startnode, startoffset} , {endnode, endoffset} } tuples. Cant store
|
||||
* ranges since dom gravity will possibly change the ranges.
|
||||
*/
|
||||
nsSelectionState::nsSelectionState() : mArray(){}
|
||||
|
||||
nsSelectionState::~nsSelectionState()
|
||||
{
|
||||
MakeEmpty();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSelectionState::SaveSelection(nsISelection *aSel)
|
||||
{
|
||||
if (!aSel) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
PRInt32 i,rangeCount, arrayCount = mArray.Count();
|
||||
nsRangeStore *item;
|
||||
aSel->GetRangeCount(&rangeCount);
|
||||
|
||||
// if we need more items in the array, new them
|
||||
if (arrayCount<rangeCount)
|
||||
{
|
||||
PRInt32 count = rangeCount-arrayCount;
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = new nsRangeStore;
|
||||
mArray.AppendElement(item);
|
||||
}
|
||||
}
|
||||
|
||||
// else if we have too many, delete them
|
||||
else if (rangeCount>arrayCount)
|
||||
{
|
||||
while ((item = (nsRangeStore*)mArray.ElementAt(rangeCount)))
|
||||
{
|
||||
delete item;
|
||||
mArray.RemoveElementAt(rangeCount);
|
||||
}
|
||||
}
|
||||
|
||||
// now store the selection ranges
|
||||
for (i=0; i<rangeCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_UNEXPECTED;
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
res = aSel->GetRangeAt(i, getter_AddRefs(range));
|
||||
item->StoreRange(range);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSelectionState::RestoreSelection(nsISelection *aSel)
|
||||
{
|
||||
if (!aSel) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
PRInt32 i, arrayCount = mArray.Count();
|
||||
nsRangeStore *item;
|
||||
|
||||
// clear out selection
|
||||
aSel->RemoveAllRanges();
|
||||
|
||||
// set the selection ranges anew
|
||||
for (i=0; i<arrayCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_UNEXPECTED;
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
item->GetRange(address_of(range));
|
||||
if (!range) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
res = aSel->AddRange(range);
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSelectionState::IsCollapsed()
|
||||
{
|
||||
if (1 != mArray.Count()) return PR_FALSE;
|
||||
nsRangeStore *item;
|
||||
item = (nsRangeStore*)mArray.ElementAt(0);
|
||||
if (!item) return PR_FALSE;
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
item->GetRange(address_of(range));
|
||||
if (!range) return PR_FALSE;
|
||||
PRBool bIsCollapsed;
|
||||
range->GetCollapsed(&bIsCollapsed);
|
||||
return bIsCollapsed;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSelectionState::IsEqual(nsSelectionState *aSelState)
|
||||
{
|
||||
if (!aSelState) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, myCount = mArray.Count(), itsCount = aSelState->mArray.Count();
|
||||
if (myCount != itsCount) return PR_FALSE;
|
||||
if (myCount < 1) return PR_FALSE;
|
||||
|
||||
nsRangeStore *myItem, *itsItem;
|
||||
|
||||
for (i=0; i<myCount; i++)
|
||||
{
|
||||
myItem = (nsRangeStore*)mArray.ElementAt(0);
|
||||
itsItem = (nsRangeStore*)(aSelState->mArray.ElementAt(0));
|
||||
if (!myItem || !itsItem) return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIDOMRange> myRange, itsRange;
|
||||
myItem->GetRange(address_of(myRange));
|
||||
itsItem->GetRange(address_of(itsRange));
|
||||
if (!myRange || !itsRange) return PR_FALSE;
|
||||
|
||||
PRInt32 compResult;
|
||||
myRange->CompareBoundaryPoints(nsIDOMRange::START_TO_START, itsRange, &compResult);
|
||||
if (compResult) return PR_FALSE;
|
||||
myRange->CompareBoundaryPoints(nsIDOMRange::END_TO_END, itsRange, &compResult);
|
||||
if (compResult) return PR_FALSE;
|
||||
}
|
||||
// if we got here, they are equal
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nsSelectionState::MakeEmpty()
|
||||
{
|
||||
// free any items in the array
|
||||
nsRangeStore *item;
|
||||
while ((item = (nsRangeStore*)mArray.ElementAt(0)))
|
||||
{
|
||||
delete item;
|
||||
mArray.RemoveElementAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSelectionState::IsEmpty()
|
||||
{
|
||||
return (mArray.Count() == 0);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* nsRangeUpdater: class for updating nsIDOMRanges in response to editor actions.
|
||||
*/
|
||||
|
||||
nsRangeUpdater::nsRangeUpdater() : mArray(), mLock(PR_FALSE) {}
|
||||
|
||||
nsRangeUpdater::~nsRangeUpdater()
|
||||
{
|
||||
// free any items in the array
|
||||
nsRangeStore *item;
|
||||
while ((item = (nsRangeStore*)mArray.ElementAt(0)))
|
||||
{
|
||||
delete item;
|
||||
mArray.RemoveElementAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
void*
|
||||
nsRangeUpdater::RegisterRange(nsIDOMRange *aRange)
|
||||
{
|
||||
nsRangeStore *item = new nsRangeStore;
|
||||
if (!item) return nsnull;
|
||||
item->StoreRange(aRange);
|
||||
mArray.AppendElement(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMRange>
|
||||
nsRangeUpdater::ReclaimRange(void *aCookie)
|
||||
{
|
||||
nsRangeStore *item = NS_STATIC_CAST(nsRangeStore*,aCookie);
|
||||
if (!item) return nsnull;
|
||||
nsCOMPtr<nsIDOMRange> outRange;
|
||||
item->GetRange(address_of(outRange));
|
||||
mArray.RemoveElement(aCookie);
|
||||
delete item;
|
||||
return outRange;
|
||||
}
|
||||
|
||||
void
|
||||
nsRangeUpdater::DropRange(void *aCookie)
|
||||
{
|
||||
nsRangeStore *item = NS_STATIC_CAST(nsRangeStore*,aCookie);
|
||||
if (!item) return;
|
||||
mArray.RemoveElement(aCookie);
|
||||
delete item;
|
||||
}
|
||||
|
||||
void
|
||||
nsRangeUpdater::RegisterRangeItem(nsRangeStore *aRangeItem)
|
||||
{
|
||||
if (!aRangeItem) return;
|
||||
mArray.AppendElement(aRangeItem);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
nsRangeUpdater::DropRangeItem(nsRangeStore *aRangeItem)
|
||||
{
|
||||
if (!aRangeItem) return;
|
||||
mArray.RemoveElement(aRangeItem);
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::RegisterSelectionState(nsSelectionState &aSelState)
|
||||
{
|
||||
PRInt32 i, theCount = aSelState.mArray.Count();
|
||||
if (theCount < 1) return NS_ERROR_FAILURE;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<theCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)aSelState.mArray.ElementAt(i);
|
||||
RegisterRangeItem(item);
|
||||
}
|
||||
|
||||
return NS_OK;;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DropSelectionState(nsSelectionState &aSelState)
|
||||
{
|
||||
PRInt32 i, theCount = aSelState.mArray.Count();
|
||||
if (theCount < 1) return NS_ERROR_FAILURE;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<theCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)aSelState.mArray.ElementAt(i);
|
||||
DropRangeItem(item);
|
||||
}
|
||||
|
||||
return NS_OK;;
|
||||
}
|
||||
|
||||
// gravity methods:
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjCreateNode(nsIDOMNode *aParent, PRInt32 aPosition)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if ((item->startNode.get() == aParent) && (item->startOffset > aPosition))
|
||||
item->startOffset++;
|
||||
if ((item->endNode.get() == aParent) && (item->endOffset > aPosition))
|
||||
item->endOffset++;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjInsertNode(nsIDOMNode *aParent, PRInt32 aPosition)
|
||||
{
|
||||
return SelAdjCreateNode(aParent, aPosition);
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjDeleteNode(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aNode) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if ((item->startNode.get() == aParent) && (item->startOffset > aOffset))
|
||||
item->startOffset--;
|
||||
if ((item->endNode.get() == aParent) && (item->endOffset > aOffset))
|
||||
item->endOffset--;
|
||||
}
|
||||
// MOOSE: also check inside of aNode, expensive. But in theory, we shouldn't
|
||||
// actually hit this case in the usage i forsee for this.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjSplitNode(nsIDOMNode *aOldRightNode, PRInt32 aOffset, nsIDOMNode *aNewLeftNode)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aOldRightNode || !aNewLeftNode) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> parent;
|
||||
PRInt32 offset;
|
||||
nsresult result = nsEditor::GetNodeLocation(aOldRightNode, address_of(parent), &offset);
|
||||
if (NS_FAILED(result)) return result;
|
||||
|
||||
// first part is same as inserting aNewLeftnode
|
||||
result = SelAdjInsertNode(parent,offset-1);
|
||||
if (NS_FAILED(result)) return result;
|
||||
|
||||
// next step is to check for range enpoints inside aOldRightNode
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (item->startNode.get() == aOldRightNode)
|
||||
{
|
||||
if (item->startOffset > aOffset)
|
||||
{
|
||||
item->startOffset -= aOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->startNode = aNewLeftNode;
|
||||
}
|
||||
}
|
||||
if (item->endNode.get() == aOldRightNode)
|
||||
{
|
||||
if (item->endOffset > aOffset)
|
||||
{
|
||||
item->endOffset -= aOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->endNode = aNewLeftNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjJoinNodes(nsIDOMNode *aLeftNode,
|
||||
nsIDOMNode *aRightNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aOffset,
|
||||
PRInt32 aOldLeftNodeLength)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aLeftNode || !aRightNode || !aParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// adjust endpoints in aParent
|
||||
if (item->startNode.get() == aParent)
|
||||
{
|
||||
if (item->startOffset > aOffset)
|
||||
{
|
||||
item->startOffset--;
|
||||
}
|
||||
else if (item->startOffset == aOffset)
|
||||
{
|
||||
// join keeps right hand node
|
||||
item->startNode = aRightNode;
|
||||
item->startOffset = aOldLeftNodeLength;
|
||||
}
|
||||
}
|
||||
if (item->endNode.get() == aParent)
|
||||
{
|
||||
if (item->endOffset > aOffset)
|
||||
{
|
||||
item->endOffset--;
|
||||
}
|
||||
else if (item->endOffset == aOffset)
|
||||
{
|
||||
// join keeps right hand node
|
||||
item->endNode = aRightNode;
|
||||
item->endOffset = aOldLeftNodeLength;
|
||||
}
|
||||
}
|
||||
// adjust endpoints in aRightNode
|
||||
if (item->startNode.get() == aRightNode)
|
||||
item->startOffset += aOldLeftNodeLength;
|
||||
if (item->endNode.get() == aRightNode)
|
||||
item->endOffset += aOldLeftNodeLength;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjInsertText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, const nsString &aString)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjDeleteText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, PRInt32 aLength)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillReplaceContainer()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidReplaceContainer(nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode)
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
|
||||
if (!aOriginalNode || !aNewNode) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (item->startNode.get() == aOriginalNode)
|
||||
item->startNode = aNewNode;
|
||||
if (item->endNode.get() == aOriginalNode)
|
||||
item->endNode = aNewNode;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillRemoveContainer()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidRemoveContainer(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset, PRUint32 aNodeOrigLen)
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
|
||||
if (!aNode || !aParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (item->startNode.get() == aNode)
|
||||
{
|
||||
item->startNode = aParent;
|
||||
item->startOffset += aOffset;
|
||||
}
|
||||
if (item->endNode.get() == aNode)
|
||||
{
|
||||
item->endNode = aParent;
|
||||
item->endOffset += aOffset;
|
||||
}
|
||||
if ((item->startNode.get() == aParent) && (item->startOffset > aOffset))
|
||||
item->startOffset += (PRInt32)aNodeOrigLen-1;
|
||||
if ((item->endNode.get() == aParent) && (item->endOffset > aOffset))
|
||||
item->endOffset += (PRInt32)aNodeOrigLen-1;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillInsertContainer()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidInsertContainer()
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillMoveNode()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidMoveNode(nsIDOMNode *aOldParent, PRInt32 aOldOffset, nsIDOMNode *aNewParent, PRInt32 aNewOffset)
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
|
||||
if (!aOldParent || !aNewParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// like a delete in aOldParent
|
||||
if ((item->startNode.get() == aOldParent) && (item->startOffset > aOldOffset))
|
||||
item->startOffset--;
|
||||
if ((item->endNode.get() == aOldParent) && (item->endOffset > aOldOffset))
|
||||
item->endOffset--;
|
||||
|
||||
// and like an insert in aNewParent
|
||||
if ((item->startNode.get() == aNewParent) && (item->startOffset > aNewOffset))
|
||||
item->startOffset++;
|
||||
if ((item->endNode.get() == aNewParent) && (item->endOffset > aNewOffset))
|
||||
item->endOffset++;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* helper class for nsSelectionState. nsRangeStore stores range endpoints.
|
||||
*/
|
||||
|
||||
// DEBUG: PRInt32 nsRangeStore::n = 0;
|
||||
|
||||
nsRangeStore::nsRangeStore()
|
||||
{
|
||||
// DEBUG: n++; printf("range store alloc count=%d\n", n);
|
||||
}
|
||||
nsRangeStore::~nsRangeStore()
|
||||
{
|
||||
// DEBUG: n--; printf("range store alloc count=%d\n", n);
|
||||
}
|
||||
|
||||
nsresult nsRangeStore::StoreRange(nsIDOMRange *aRange)
|
||||
{
|
||||
if (!aRange) return NS_ERROR_NULL_POINTER;
|
||||
aRange->GetStartContainer(getter_AddRefs(startNode));
|
||||
aRange->GetEndContainer(getter_AddRefs(endNode));
|
||||
aRange->GetStartOffset(&startOffset);
|
||||
aRange->GetEndOffset(&endOffset);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsRangeStore::GetRange(nsCOMPtr<nsIDOMRange> *outRange)
|
||||
{
|
||||
if (!outRange) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = nsComponentManager::CreateInstance(kCRangeCID,
|
||||
nsnull,
|
||||
NS_GET_IID(nsIDOMRange),
|
||||
getter_AddRefs(*outRange));
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
res = (*outRange)->SetStart(startNode, startOffset);
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
res = (*outRange)->SetEnd(endNode, endOffset);
|
||||
return res;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidReplaceContainer()
|
||||
*/
|
||||
|
||||
class nsAutoReplaceContainerSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
nsIDOMNode *mOriginalNode;
|
||||
nsIDOMNode *mNewNode;
|
||||
|
||||
public:
|
||||
nsAutoReplaceContainerSelNotify(nsRangeUpdater &aRangeUpdater, nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode) :
|
||||
mRU(aRangeUpdater)
|
||||
,mOriginalNode(aOriginalNode)
|
||||
,mNewNode(aNewNode)
|
||||
{
|
||||
mRU.WillReplaceContainer();
|
||||
}
|
||||
|
||||
~nsAutoReplaceContainerSelNotify()
|
||||
{
|
||||
mRU.DidReplaceContainer(mOriginalNode, mNewNode);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidRemoveContainer()
|
||||
*/
|
||||
|
||||
class nsAutoRemoveContainerSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
nsIDOMNode *mNode;
|
||||
nsIDOMNode *mParent;
|
||||
PRInt32 mOffset;
|
||||
PRUint32 mNodeOrigLen;
|
||||
|
||||
public:
|
||||
nsAutoRemoveContainerSelNotify(nsRangeUpdater &aRangeUpdater,
|
||||
nsIDOMNode *aNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aOffset,
|
||||
PRUint32 aNodeOrigLen) :
|
||||
mRU(aRangeUpdater)
|
||||
,mNode(aNode)
|
||||
,mParent(aParent)
|
||||
,mOffset(aOffset)
|
||||
,mNodeOrigLen(aNodeOrigLen)
|
||||
{
|
||||
mRU.WillRemoveContainer();
|
||||
}
|
||||
|
||||
~nsAutoRemoveContainerSelNotify()
|
||||
{
|
||||
mRU.DidRemoveContainer(mNode, mParent, mOffset, mNodeOrigLen);
|
||||
}
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidInsertContainer()
|
||||
*/
|
||||
|
||||
class nsAutoInsertContainerSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
|
||||
public:
|
||||
nsAutoInsertContainerSelNotify(nsRangeUpdater &aRangeUpdater) :
|
||||
mRU(aRangeUpdater)
|
||||
{
|
||||
mRU.WillInsertContainer();
|
||||
}
|
||||
|
||||
~nsAutoInsertContainerSelNotify()
|
||||
{
|
||||
mRU.DidInsertContainer();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidMoveNode()
|
||||
*/
|
||||
|
||||
class nsAutoMoveNodeSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
nsIDOMNode *mOldParent;
|
||||
nsIDOMNode *mNewParent;
|
||||
PRInt32 mOldOffset;
|
||||
PRInt32 mNewOffset;
|
||||
|
||||
public:
|
||||
nsAutoMoveNodeSelNotify(nsRangeUpdater &aRangeUpdater,
|
||||
nsIDOMNode *aOldParent,
|
||||
PRInt32 aOldOffset,
|
||||
nsIDOMNode *aNewParent,
|
||||
PRInt32 aNewOffset) :
|
||||
mRU(aRangeUpdater)
|
||||
,mOldParent(aOldParent)
|
||||
,mNewParent(aNewParent)
|
||||
,mOldOffset(aOldOffset)
|
||||
,mNewOffset(aNewOffset)
|
||||
{
|
||||
mRU.WillMoveNode();
|
||||
}
|
||||
|
||||
~nsAutoMoveNodeSelNotify()
|
||||
{
|
||||
mRU.DidMoveNode(mOldParent, mOldOffset, mNewParent, mNewOffset);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// nsEditor: base editor class implementation
|
||||
@ -2606,7 +1875,7 @@ nsEditor::ForceCompositionEnd()
|
||||
#endif
|
||||
|
||||
#ifdef XP_UNIX
|
||||
if(mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
||||
if(mFlags & nsIPlaintextEditor::eEditorPasswordMask)
|
||||
return NS_OK;
|
||||
#endif
|
||||
|
||||
@ -5059,7 +4328,6 @@ nsEditor::IsNextCharWhitespace(nsIDOMNode *aParentNode,
|
||||
textNode->GetLength(&strLength);
|
||||
if (strLength)
|
||||
{
|
||||
// you could use nsITextContent::IsOnlyWhitespace here
|
||||
textNode->SubstringData(0,1,tempString);
|
||||
*outIsSpace = nsCRT::IsAsciiSpace(tempString.First());
|
||||
*outIsNBSP = (tempString.First() == nbsp);
|
||||
@ -5391,7 +4659,7 @@ nsresult nsEditor::EndUpdateViewBatch()
|
||||
|
||||
PRBool forceReflow = PR_TRUE;
|
||||
|
||||
if (flags & nsIHTMLEditor::eEditorDisableForcedReflowsMask)
|
||||
if (flags & nsIPlaintextEditor::eEditorDisableForcedReflowsMask)
|
||||
forceReflow = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
@ -5401,7 +4669,7 @@ nsresult nsEditor::EndUpdateViewBatch()
|
||||
|
||||
PRUint32 updateFlag = NS_VMREFRESH_IMMEDIATE;
|
||||
|
||||
if (flags & nsIHTMLEditor::eEditorDisableForcedUpdatesMask)
|
||||
if (flags & nsIPlaintextEditor::eEditorDisableForcedUpdatesMask)
|
||||
updateFlag = NS_VMREFRESH_NO_SYNC;
|
||||
|
||||
#ifdef HACK_FORCE_REDRAW
|
||||
@ -5482,9 +4750,129 @@ nsEditor::DeleteSelectionImpl(nsIEditor::EDirection aAction)
|
||||
return res;
|
||||
}
|
||||
|
||||
// XXX: error handling in this routine needs to be cleaned up!
|
||||
NS_IMETHODIMP
|
||||
nsEditor::DeleteSelectionAndCreateNode(const nsString& aTag,
|
||||
nsIDOMNode ** aNewNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> parentSelectedNode;
|
||||
PRInt32 offsetOfNewNode;
|
||||
nsresult result = DeleteSelectionAndPrepareToCreateNode(parentSelectedNode,
|
||||
offsetOfNewNode);
|
||||
if (!NS_SUCCEEDED(result))
|
||||
return result;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
result = CreateNode(aTag, parentSelectedNode, offsetOfNewNode,
|
||||
getter_AddRefs(newNode));
|
||||
// XXX: ERROR_HANDLING check result, and make sure aNewNode is set correctly in success/failure cases
|
||||
*aNewNode = newNode;
|
||||
NS_IF_ADDREF(*aNewNode);
|
||||
|
||||
// we want the selection to be just after the new node
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
result = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(result)) return result;
|
||||
if (!selection) return NS_ERROR_NULL_POINTER;
|
||||
result = selection->Collapse(parentSelectedNode, offsetOfNewNode+1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Non-interface, protected methods */
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNode> &parentSelectedNode, PRInt32& offsetOfNewNode)
|
||||
{
|
||||
nsresult result=NS_ERROR_NOT_INITIALIZED;
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
result = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(result)) return result;
|
||||
if (!selection) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
PRBool collapsed;
|
||||
result = selection->GetIsCollapsed(&collapsed);
|
||||
if (NS_SUCCEEDED(result) && !collapsed)
|
||||
{
|
||||
result = DeleteSelection(nsIEditor::eNone);
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
// get the new selection
|
||||
result = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
#ifdef NS_DEBUG
|
||||
nsCOMPtr<nsIDOMNode>testSelectedNode;
|
||||
nsresult debugResult = selection->GetAnchorNode(getter_AddRefs(testSelectedNode));
|
||||
// no selection is ok.
|
||||
// if there is a selection, it must be collapsed
|
||||
if (testSelectedNode)
|
||||
{
|
||||
PRBool testCollapsed;
|
||||
debugResult = selection->GetIsCollapsed(&testCollapsed);
|
||||
NS_ASSERTION((NS_SUCCEEDED(result)), "couldn't get a selection after deletion");
|
||||
NS_ASSERTION(testCollapsed, "selection not reset after deletion");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// split the selected node
|
||||
PRInt32 offsetOfSelectedNode;
|
||||
result = selection->GetAnchorNode(getter_AddRefs(parentSelectedNode));
|
||||
if (NS_SUCCEEDED(result) && NS_SUCCEEDED(selection->GetAnchorOffset(&offsetOfSelectedNode)) && parentSelectedNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> selectedNode;
|
||||
PRUint32 selectedNodeContentCount=0;
|
||||
nsCOMPtr<nsIDOMCharacterData>selectedParentNodeAsText;
|
||||
selectedParentNodeAsText = do_QueryInterface(parentSelectedNode);
|
||||
|
||||
offsetOfNewNode = offsetOfSelectedNode;
|
||||
|
||||
/* if the selection is a text node, split the text node if necesary
|
||||
and compute where to put the new node
|
||||
*/
|
||||
if (selectedParentNodeAsText)
|
||||
{
|
||||
PRInt32 indexOfTextNodeInParent;
|
||||
selectedNode = do_QueryInterface(parentSelectedNode);
|
||||
selectedNode->GetParentNode(getter_AddRefs(parentSelectedNode));
|
||||
selectedParentNodeAsText->GetLength(&selectedNodeContentCount);
|
||||
GetChildOffset(selectedNode, parentSelectedNode, indexOfTextNodeInParent);
|
||||
|
||||
if ((offsetOfSelectedNode!=0) && (((PRUint32)offsetOfSelectedNode)!=selectedNodeContentCount))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> newSiblingNode;
|
||||
result = SplitNode(selectedNode, offsetOfSelectedNode, getter_AddRefs(newSiblingNode));
|
||||
// now get the node's offset in it's parent, and insert the new tag there
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
result = GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // determine where to insert the new node
|
||||
if (0==offsetOfSelectedNode) {
|
||||
offsetOfNewNode = indexOfTextNodeInParent; // insert new node as previous sibling to selection parent
|
||||
}
|
||||
else { // insert new node as last child
|
||||
GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
|
||||
offsetOfNewNode++; // offsets are 0-based, and we need the index of the new node
|
||||
}
|
||||
}
|
||||
}
|
||||
// Here's where the new node was inserted
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else {
|
||||
printf("InsertLineBreak into an empty document is not yet supported\n");
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::DoAfterDoTransaction(nsITransaction *aTxn)
|
||||
{
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "nsIDTD.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsSelectionState.h"
|
||||
|
||||
class nsIEditActionListener;
|
||||
class nsIDocumentStateListener;
|
||||
@ -72,92 +73,6 @@ class nsIFile;
|
||||
class nsISelectionController;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* class for recording selection info. stores selection as collection of
|
||||
* { {startnode, startoffset} , {endnode, endoffset} } tuples. Cant store
|
||||
* ranges since dom gravity will possibly change the ranges.
|
||||
*/
|
||||
|
||||
// first a helper struct for saving/setting ranges
|
||||
struct nsRangeStore
|
||||
{
|
||||
nsRangeStore();
|
||||
~nsRangeStore();
|
||||
nsresult StoreRange(nsIDOMRange *aRange);
|
||||
nsresult GetRange(nsCOMPtr<nsIDOMRange> *outRange);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> startNode;
|
||||
PRInt32 startOffset;
|
||||
nsCOMPtr<nsIDOMNode> endNode;
|
||||
PRInt32 endOffset;
|
||||
// DEBUG: static PRInt32 n;
|
||||
};
|
||||
|
||||
class nsSelectionState
|
||||
{
|
||||
public:
|
||||
|
||||
nsSelectionState();
|
||||
~nsSelectionState();
|
||||
|
||||
nsresult SaveSelection(nsISelection *aSel);
|
||||
nsresult RestoreSelection(nsISelection *aSel);
|
||||
PRBool IsCollapsed();
|
||||
PRBool IsEqual(nsSelectionState *aSelState);
|
||||
void MakeEmpty();
|
||||
PRBool IsEmpty();
|
||||
protected:
|
||||
nsVoidArray mArray;
|
||||
|
||||
friend class nsRangeUpdater;
|
||||
};
|
||||
|
||||
class nsRangeUpdater
|
||||
{
|
||||
public:
|
||||
|
||||
nsRangeUpdater();
|
||||
~nsRangeUpdater();
|
||||
|
||||
void* RegisterRange(nsIDOMRange *aRange);
|
||||
nsCOMPtr<nsIDOMRange> ReclaimRange(void *aCookie);
|
||||
void DropRange(void *aCookie);
|
||||
void RegisterRangeItem(nsRangeStore *aRangeItem);
|
||||
void DropRangeItem(nsRangeStore *aRangeItem);
|
||||
nsresult RegisterSelectionState(nsSelectionState &aSelState);
|
||||
nsresult DropSelectionState(nsSelectionState &aSelState);
|
||||
|
||||
// editor selection gravity routines. Note that we can't always depend on
|
||||
// DOM Range gravity to do what we want to the "real" selection. For instance,
|
||||
// if you move a node, that corresponds to deleting it and reinserting it.
|
||||
// DOM Range gravity will promote the selection out of the node on deletion,
|
||||
// which is not what you want if you know you are reinserting it.
|
||||
nsresult SelAdjCreateNode(nsIDOMNode *aParent, PRInt32 aPosition);
|
||||
nsresult SelAdjInsertNode(nsIDOMNode *aParent, PRInt32 aPosition);
|
||||
nsresult SelAdjDeleteNode(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset);
|
||||
nsresult SelAdjSplitNode(nsIDOMNode *aOldRightNode, PRInt32 aOffset, nsIDOMNode *aNewLeftNode);
|
||||
nsresult SelAdjJoinNodes(nsIDOMNode *aLeftNode,
|
||||
nsIDOMNode *aRightNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aOffset,
|
||||
PRInt32 aOldLeftNodeLength);
|
||||
nsresult SelAdjInsertText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, const nsString &aString);
|
||||
nsresult SelAdjDeleteText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, PRInt32 aLength);
|
||||
// the following gravity routines need will/did sandwiches, because the other gravity
|
||||
// routines will be called inside of these sandwiches, but should be ignored.
|
||||
nsresult WillReplaceContainer();
|
||||
nsresult DidReplaceContainer(nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode);
|
||||
nsresult WillRemoveContainer();
|
||||
nsresult DidRemoveContainer(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset, PRUint32 aNodeOrigLen);
|
||||
nsresult WillInsertContainer();
|
||||
nsresult DidInsertContainer();
|
||||
nsresult WillMoveNode();
|
||||
nsresult DidMoveNode(nsIDOMNode *aOldParent, PRInt32 aOldOffset, nsIDOMNode *aNewParent, PRInt32 aNewOffset);
|
||||
protected:
|
||||
nsVoidArray mArray;
|
||||
PRBool mLock;
|
||||
};
|
||||
|
||||
/** implementation of an editor object. it will be the controller/focal point
|
||||
* for the main editor services. i.e. the GUIManager, publishing, transaction
|
||||
* manager, event interfaces. the idea for the event interfaces is to have them
|
||||
@ -181,18 +96,17 @@ public:
|
||||
kOpNone = 0,
|
||||
kOpUndo,
|
||||
kOpRedo,
|
||||
kOpSetTextProperty,
|
||||
kOpRemoveTextProperty,
|
||||
kOpInsertNode,
|
||||
kOpCreateNode,
|
||||
kOpDeleteNode,
|
||||
kOpSplitNode,
|
||||
kOpJoinNode,
|
||||
kOpDeleteText,
|
||||
kOpInsertText,
|
||||
kOpInsertIMEText,
|
||||
kOpDeleteSelection,
|
||||
kOpHTMLPaste
|
||||
// text commands
|
||||
kOpInsertBreak = 1000,
|
||||
kOpInsertText = 1001,
|
||||
kOpInsertIMEText = 1002,
|
||||
kOpDeleteText = 1003
|
||||
};
|
||||
|
||||
static const char* kMOZEditorBogusNodeAttr;
|
||||
@ -341,6 +255,8 @@ public:
|
||||
nsIDOMCharacterData *aTextNode,
|
||||
PRInt32 aOffset);
|
||||
NS_IMETHOD DeleteSelectionImpl(EDirection aAction);
|
||||
NS_IMETHOD DeleteSelectionAndCreateNode(const nsString& aTag,
|
||||
nsIDOMNode ** aNewNode);
|
||||
|
||||
/* helper routines for node/parent manipulations */
|
||||
nsresult ReplaceContainer(nsIDOMNode *inNode,
|
||||
@ -454,6 +370,8 @@ protected:
|
||||
nsIDOMNode *aRightNode,
|
||||
JoinElementTxn **aTxn);
|
||||
|
||||
NS_IMETHOD DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNode> &parentSelectedNode,
|
||||
PRInt32& offsetOfNewNode);
|
||||
|
||||
// called each time we modify the document. Increments the mod
|
||||
// count of the doc.
|
||||
@ -775,7 +693,7 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
PRUint32 mFlags; // behavior flags. See nsIHTMLEditor.h for the flags we use.
|
||||
PRUint32 mFlags; // behavior flags. See nsPlaintextEditor.h for the flags we use.
|
||||
|
||||
nsWeakPtr mPresShellWeak; // weak reference to the nsIPresShell
|
||||
nsWeakPtr mSelConWeak; // weak reference to the nsISelectionController
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "nsIAtom.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsEditor.h"
|
||||
#include "nsPlaintextEditor.h"
|
||||
#include "nsIContentIterator.h"
|
||||
|
||||
/***************************************************************************
|
||||
@ -48,6 +49,22 @@ class nsAutoPlaceHolderBatch
|
||||
~nsAutoPlaceHolderBatch() { if (mEd) mEd->EndPlaceHolderTransaction(); }
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
* stack based helper class for detecting end of editor initialization, in
|
||||
* order to triger "end of init" initialization of the edit rules.
|
||||
*/
|
||||
class nsAutoEditInitRulesTrigger
|
||||
{
|
||||
private:
|
||||
nsPlaintextEditor *mEd;
|
||||
nsresult &mRes;
|
||||
public:
|
||||
nsAutoEditInitRulesTrigger( nsPlaintextEditor *aEd, nsresult &aRes) : mEd(aEd), mRes(aRes)
|
||||
{ if (mEd) mEd->BeginEditorInit(); }
|
||||
~nsAutoEditInitRulesTrigger() { if (mEd) mRes = mEd->EndEditorInit(); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* stack based helper class for batching a collection of txns.
|
||||
|
640
editor/libeditor/base/nsSelectionState.cpp
Normal file
640
editor/libeditor/base/nsSelectionState.cpp
Normal file
@ -0,0 +1,640 @@
|
||||
/* -*- 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.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nsSelectionState.h"
|
||||
#include "nsIDOMCharacterData.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsIDOMRange.h"
|
||||
#include "nsISelection.h"
|
||||
#include "nsEditor.h"
|
||||
#include "nsLayoutCID.h"
|
||||
|
||||
static NS_DEFINE_CID(kCRangeCID, NS_RANGE_CID);
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* class for recording selection info. stores selection as collection of
|
||||
* { {startnode, startoffset} , {endnode, endoffset} } tuples. Cant store
|
||||
* ranges since dom gravity will possibly change the ranges.
|
||||
*/
|
||||
nsSelectionState::nsSelectionState() : mArray(){}
|
||||
|
||||
nsSelectionState::~nsSelectionState()
|
||||
{
|
||||
MakeEmpty();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSelectionState::SaveSelection(nsISelection *aSel)
|
||||
{
|
||||
if (!aSel) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
PRInt32 i,rangeCount, arrayCount = mArray.Count();
|
||||
nsRangeStore *item;
|
||||
aSel->GetRangeCount(&rangeCount);
|
||||
|
||||
// if we need more items in the array, new them
|
||||
if (arrayCount<rangeCount)
|
||||
{
|
||||
PRInt32 count = rangeCount-arrayCount;
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = new nsRangeStore;
|
||||
mArray.AppendElement(item);
|
||||
}
|
||||
}
|
||||
|
||||
// else if we have too many, delete them
|
||||
else if (rangeCount>arrayCount)
|
||||
{
|
||||
while ((item = (nsRangeStore*)mArray.ElementAt(rangeCount)))
|
||||
{
|
||||
delete item;
|
||||
mArray.RemoveElementAt(rangeCount);
|
||||
}
|
||||
}
|
||||
|
||||
// now store the selection ranges
|
||||
for (i=0; i<rangeCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_UNEXPECTED;
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
res = aSel->GetRangeAt(i, getter_AddRefs(range));
|
||||
item->StoreRange(range);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSelectionState::RestoreSelection(nsISelection *aSel)
|
||||
{
|
||||
if (!aSel) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
PRInt32 i, arrayCount = mArray.Count();
|
||||
nsRangeStore *item;
|
||||
|
||||
// clear out selection
|
||||
aSel->RemoveAllRanges();
|
||||
|
||||
// set the selection ranges anew
|
||||
for (i=0; i<arrayCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_UNEXPECTED;
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
item->GetRange(address_of(range));
|
||||
if (!range) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
res = aSel->AddRange(range);
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSelectionState::IsCollapsed()
|
||||
{
|
||||
if (1 != mArray.Count()) return PR_FALSE;
|
||||
nsRangeStore *item;
|
||||
item = (nsRangeStore*)mArray.ElementAt(0);
|
||||
if (!item) return PR_FALSE;
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
item->GetRange(address_of(range));
|
||||
if (!range) return PR_FALSE;
|
||||
PRBool bIsCollapsed;
|
||||
range->GetCollapsed(&bIsCollapsed);
|
||||
return bIsCollapsed;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSelectionState::IsEqual(nsSelectionState *aSelState)
|
||||
{
|
||||
if (!aSelState) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, myCount = mArray.Count(), itsCount = aSelState->mArray.Count();
|
||||
if (myCount != itsCount) return PR_FALSE;
|
||||
if (myCount < 1) return PR_FALSE;
|
||||
|
||||
nsRangeStore *myItem, *itsItem;
|
||||
|
||||
for (i=0; i<myCount; i++)
|
||||
{
|
||||
myItem = (nsRangeStore*)mArray.ElementAt(0);
|
||||
itsItem = (nsRangeStore*)(aSelState->mArray.ElementAt(0));
|
||||
if (!myItem || !itsItem) return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIDOMRange> myRange, itsRange;
|
||||
myItem->GetRange(address_of(myRange));
|
||||
itsItem->GetRange(address_of(itsRange));
|
||||
if (!myRange || !itsRange) return PR_FALSE;
|
||||
|
||||
PRInt32 compResult;
|
||||
myRange->CompareBoundaryPoints(nsIDOMRange::START_TO_START, itsRange, &compResult);
|
||||
if (compResult) return PR_FALSE;
|
||||
myRange->CompareBoundaryPoints(nsIDOMRange::END_TO_END, itsRange, &compResult);
|
||||
if (compResult) return PR_FALSE;
|
||||
}
|
||||
// if we got here, they are equal
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nsSelectionState::MakeEmpty()
|
||||
{
|
||||
// free any items in the array
|
||||
nsRangeStore *item;
|
||||
while ((item = (nsRangeStore*)mArray.ElementAt(0)))
|
||||
{
|
||||
delete item;
|
||||
mArray.RemoveElementAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSelectionState::IsEmpty()
|
||||
{
|
||||
return (mArray.Count() == 0);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* nsRangeUpdater: class for updating nsIDOMRanges in response to editor actions.
|
||||
*/
|
||||
|
||||
nsRangeUpdater::nsRangeUpdater() : mArray(), mLock(PR_FALSE) {}
|
||||
|
||||
nsRangeUpdater::~nsRangeUpdater()
|
||||
{
|
||||
// free any items in the array
|
||||
nsRangeStore *item;
|
||||
while ((item = (nsRangeStore*)mArray.ElementAt(0)))
|
||||
{
|
||||
delete item;
|
||||
mArray.RemoveElementAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
void*
|
||||
nsRangeUpdater::RegisterRange(nsIDOMRange *aRange)
|
||||
{
|
||||
nsRangeStore *item = new nsRangeStore;
|
||||
if (!item) return nsnull;
|
||||
item->StoreRange(aRange);
|
||||
mArray.AppendElement(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMRange>
|
||||
nsRangeUpdater::ReclaimRange(void *aCookie)
|
||||
{
|
||||
nsRangeStore *item = NS_STATIC_CAST(nsRangeStore*,aCookie);
|
||||
if (!item) return nsnull;
|
||||
nsCOMPtr<nsIDOMRange> outRange;
|
||||
item->GetRange(address_of(outRange));
|
||||
mArray.RemoveElement(aCookie);
|
||||
delete item;
|
||||
return outRange;
|
||||
}
|
||||
|
||||
void
|
||||
nsRangeUpdater::DropRange(void *aCookie)
|
||||
{
|
||||
nsRangeStore *item = NS_STATIC_CAST(nsRangeStore*,aCookie);
|
||||
if (!item) return;
|
||||
mArray.RemoveElement(aCookie);
|
||||
delete item;
|
||||
}
|
||||
|
||||
void
|
||||
nsRangeUpdater::RegisterRangeItem(nsRangeStore *aRangeItem)
|
||||
{
|
||||
if (!aRangeItem) return;
|
||||
mArray.AppendElement(aRangeItem);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
nsRangeUpdater::DropRangeItem(nsRangeStore *aRangeItem)
|
||||
{
|
||||
if (!aRangeItem) return;
|
||||
mArray.RemoveElement(aRangeItem);
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::RegisterSelectionState(nsSelectionState &aSelState)
|
||||
{
|
||||
PRInt32 i, theCount = aSelState.mArray.Count();
|
||||
if (theCount < 1) return NS_ERROR_FAILURE;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<theCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)aSelState.mArray.ElementAt(i);
|
||||
RegisterRangeItem(item);
|
||||
}
|
||||
|
||||
return NS_OK;;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DropSelectionState(nsSelectionState &aSelState)
|
||||
{
|
||||
PRInt32 i, theCount = aSelState.mArray.Count();
|
||||
if (theCount < 1) return NS_ERROR_FAILURE;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<theCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)aSelState.mArray.ElementAt(i);
|
||||
DropRangeItem(item);
|
||||
}
|
||||
|
||||
return NS_OK;;
|
||||
}
|
||||
|
||||
// gravity methods:
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjCreateNode(nsIDOMNode *aParent, PRInt32 aPosition)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if ((item->startNode.get() == aParent) && (item->startOffset > aPosition))
|
||||
item->startOffset++;
|
||||
if ((item->endNode.get() == aParent) && (item->endOffset > aPosition))
|
||||
item->endOffset++;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjInsertNode(nsIDOMNode *aParent, PRInt32 aPosition)
|
||||
{
|
||||
return SelAdjCreateNode(aParent, aPosition);
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjDeleteNode(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aNode) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if ((item->startNode.get() == aParent) && (item->startOffset > aOffset))
|
||||
item->startOffset--;
|
||||
if ((item->endNode.get() == aParent) && (item->endOffset > aOffset))
|
||||
item->endOffset--;
|
||||
}
|
||||
// MOOSE: also check inside of aNode, expensive. But in theory, we shouldn't
|
||||
// actually hit this case in the usage i forsee for this.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjSplitNode(nsIDOMNode *aOldRightNode, PRInt32 aOffset, nsIDOMNode *aNewLeftNode)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aOldRightNode || !aNewLeftNode) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> parent;
|
||||
PRInt32 offset;
|
||||
nsresult result = nsEditor::GetNodeLocation(aOldRightNode, address_of(parent), &offset);
|
||||
if (NS_FAILED(result)) return result;
|
||||
|
||||
// first part is same as inserting aNewLeftnode
|
||||
result = SelAdjInsertNode(parent,offset-1);
|
||||
if (NS_FAILED(result)) return result;
|
||||
|
||||
// next step is to check for range enpoints inside aOldRightNode
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (item->startNode.get() == aOldRightNode)
|
||||
{
|
||||
if (item->startOffset > aOffset)
|
||||
{
|
||||
item->startOffset -= aOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->startNode = aNewLeftNode;
|
||||
}
|
||||
}
|
||||
if (item->endNode.get() == aOldRightNode)
|
||||
{
|
||||
if (item->endOffset > aOffset)
|
||||
{
|
||||
item->endOffset -= aOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->endNode = aNewLeftNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjJoinNodes(nsIDOMNode *aLeftNode,
|
||||
nsIDOMNode *aRightNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aOffset,
|
||||
PRInt32 aOldLeftNodeLength)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aLeftNode || !aRightNode || !aParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// adjust endpoints in aParent
|
||||
if (item->startNode.get() == aParent)
|
||||
{
|
||||
if (item->startOffset > aOffset)
|
||||
{
|
||||
item->startOffset--;
|
||||
}
|
||||
else if (item->startOffset == aOffset)
|
||||
{
|
||||
// join keeps right hand node
|
||||
item->startNode = aRightNode;
|
||||
item->startOffset = aOldLeftNodeLength;
|
||||
}
|
||||
}
|
||||
if (item->endNode.get() == aParent)
|
||||
{
|
||||
if (item->endOffset > aOffset)
|
||||
{
|
||||
item->endOffset--;
|
||||
}
|
||||
else if (item->endOffset == aOffset)
|
||||
{
|
||||
// join keeps right hand node
|
||||
item->endNode = aRightNode;
|
||||
item->endOffset = aOldLeftNodeLength;
|
||||
}
|
||||
}
|
||||
// adjust endpoints in aRightNode
|
||||
if (item->startNode.get() == aRightNode)
|
||||
item->startOffset += aOldLeftNodeLength;
|
||||
if (item->endNode.get() == aRightNode)
|
||||
item->endOffset += aOldLeftNodeLength;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjInsertText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, const nsString &aString)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjDeleteText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, PRInt32 aLength)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillReplaceContainer()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidReplaceContainer(nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode)
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
|
||||
if (!aOriginalNode || !aNewNode) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (item->startNode.get() == aOriginalNode)
|
||||
item->startNode = aNewNode;
|
||||
if (item->endNode.get() == aOriginalNode)
|
||||
item->endNode = aNewNode;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillRemoveContainer()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidRemoveContainer(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset, PRUint32 aNodeOrigLen)
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
|
||||
if (!aNode || !aParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (item->startNode.get() == aNode)
|
||||
{
|
||||
item->startNode = aParent;
|
||||
item->startOffset += aOffset;
|
||||
}
|
||||
if (item->endNode.get() == aNode)
|
||||
{
|
||||
item->endNode = aParent;
|
||||
item->endOffset += aOffset;
|
||||
}
|
||||
if ((item->startNode.get() == aParent) && (item->startOffset > aOffset))
|
||||
item->startOffset += (PRInt32)aNodeOrigLen-1;
|
||||
if ((item->endNode.get() == aParent) && (item->endOffset > aOffset))
|
||||
item->endOffset += (PRInt32)aNodeOrigLen-1;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillInsertContainer()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidInsertContainer()
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillMoveNode()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidMoveNode(nsIDOMNode *aOldParent, PRInt32 aOldOffset, nsIDOMNode *aNewParent, PRInt32 aNewOffset)
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
|
||||
if (!aOldParent || !aNewParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// like a delete in aOldParent
|
||||
if ((item->startNode.get() == aOldParent) && (item->startOffset > aOldOffset))
|
||||
item->startOffset--;
|
||||
if ((item->endNode.get() == aOldParent) && (item->endOffset > aOldOffset))
|
||||
item->endOffset--;
|
||||
|
||||
// and like an insert in aNewParent
|
||||
if ((item->startNode.get() == aNewParent) && (item->startOffset > aNewOffset))
|
||||
item->startOffset++;
|
||||
if ((item->endNode.get() == aNewParent) && (item->endOffset > aNewOffset))
|
||||
item->endOffset++;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* helper class for nsSelectionState. nsRangeStore stores range endpoints.
|
||||
*/
|
||||
|
||||
// DEBUG: PRInt32 nsRangeStore::n = 0;
|
||||
|
||||
nsRangeStore::nsRangeStore()
|
||||
{
|
||||
// DEBUG: n++; printf("range store alloc count=%d\n", n);
|
||||
}
|
||||
nsRangeStore::~nsRangeStore()
|
||||
{
|
||||
// DEBUG: n--; printf("range store alloc count=%d\n", n);
|
||||
}
|
||||
|
||||
nsresult nsRangeStore::StoreRange(nsIDOMRange *aRange)
|
||||
{
|
||||
if (!aRange) return NS_ERROR_NULL_POINTER;
|
||||
aRange->GetStartContainer(getter_AddRefs(startNode));
|
||||
aRange->GetEndContainer(getter_AddRefs(endNode));
|
||||
aRange->GetStartOffset(&startOffset);
|
||||
aRange->GetEndOffset(&endOffset);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsRangeStore::GetRange(nsCOMPtr<nsIDOMRange> *outRange)
|
||||
{
|
||||
if (!outRange) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = nsComponentManager::CreateInstance(kCRangeCID,
|
||||
nsnull,
|
||||
NS_GET_IID(nsIDOMRange),
|
||||
getter_AddRefs(*outRange));
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
res = (*outRange)->SetStart(startNode, startOffset);
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
res = (*outRange)->SetEnd(endNode, endOffset);
|
||||
return res;
|
||||
}
|
245
editor/libeditor/base/nsSelectionState.h
Normal file
245
editor/libeditor/base/nsSelectionState.h
Normal file
@ -0,0 +1,245 @@
|
||||
/* -*- 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.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#ifndef __selectionstate_h__
|
||||
#define __selectionstate_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsIDOMNode.h"
|
||||
|
||||
class nsIDOMCharacterData;
|
||||
class nsIDOMRange;
|
||||
class nsISelection;
|
||||
|
||||
/***************************************************************************
|
||||
* class for recording selection info. stores selection as collection of
|
||||
* { {startnode, startoffset} , {endnode, endoffset} } tuples. Cant store
|
||||
* ranges since dom gravity will possibly change the ranges.
|
||||
*/
|
||||
|
||||
// first a helper struct for saving/setting ranges
|
||||
struct nsRangeStore
|
||||
{
|
||||
nsRangeStore();
|
||||
~nsRangeStore();
|
||||
nsresult StoreRange(nsIDOMRange *aRange);
|
||||
nsresult GetRange(nsCOMPtr<nsIDOMRange> *outRange);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> startNode;
|
||||
PRInt32 startOffset;
|
||||
nsCOMPtr<nsIDOMNode> endNode;
|
||||
PRInt32 endOffset;
|
||||
// DEBUG: static PRInt32 n;
|
||||
};
|
||||
|
||||
class nsSelectionState
|
||||
{
|
||||
public:
|
||||
|
||||
nsSelectionState();
|
||||
~nsSelectionState();
|
||||
|
||||
nsresult SaveSelection(nsISelection *aSel);
|
||||
nsresult RestoreSelection(nsISelection *aSel);
|
||||
PRBool IsCollapsed();
|
||||
PRBool IsEqual(nsSelectionState *aSelState);
|
||||
void MakeEmpty();
|
||||
PRBool IsEmpty();
|
||||
protected:
|
||||
nsVoidArray mArray;
|
||||
|
||||
friend class nsRangeUpdater;
|
||||
};
|
||||
|
||||
class nsRangeUpdater
|
||||
{
|
||||
public:
|
||||
|
||||
nsRangeUpdater();
|
||||
~nsRangeUpdater();
|
||||
|
||||
void* RegisterRange(nsIDOMRange *aRange);
|
||||
nsCOMPtr<nsIDOMRange> ReclaimRange(void *aCookie);
|
||||
void DropRange(void *aCookie);
|
||||
void RegisterRangeItem(nsRangeStore *aRangeItem);
|
||||
void DropRangeItem(nsRangeStore *aRangeItem);
|
||||
nsresult RegisterSelectionState(nsSelectionState &aSelState);
|
||||
nsresult DropSelectionState(nsSelectionState &aSelState);
|
||||
|
||||
// editor selection gravity routines. Note that we can't always depend on
|
||||
// DOM Range gravity to do what we want to the "real" selection. For instance,
|
||||
// if you move a node, that corresponds to deleting it and reinserting it.
|
||||
// DOM Range gravity will promote the selection out of the node on deletion,
|
||||
// which is not what you want if you know you are reinserting it.
|
||||
nsresult SelAdjCreateNode(nsIDOMNode *aParent, PRInt32 aPosition);
|
||||
nsresult SelAdjInsertNode(nsIDOMNode *aParent, PRInt32 aPosition);
|
||||
nsresult SelAdjDeleteNode(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset);
|
||||
nsresult SelAdjSplitNode(nsIDOMNode *aOldRightNode, PRInt32 aOffset, nsIDOMNode *aNewLeftNode);
|
||||
nsresult SelAdjJoinNodes(nsIDOMNode *aLeftNode,
|
||||
nsIDOMNode *aRightNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aOffset,
|
||||
PRInt32 aOldLeftNodeLength);
|
||||
nsresult SelAdjInsertText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, const nsString &aString);
|
||||
nsresult SelAdjDeleteText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, PRInt32 aLength);
|
||||
// the following gravity routines need will/did sandwiches, because the other gravity
|
||||
// routines will be called inside of these sandwiches, but should be ignored.
|
||||
nsresult WillReplaceContainer();
|
||||
nsresult DidReplaceContainer(nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode);
|
||||
nsresult WillRemoveContainer();
|
||||
nsresult DidRemoveContainer(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset, PRUint32 aNodeOrigLen);
|
||||
nsresult WillInsertContainer();
|
||||
nsresult DidInsertContainer();
|
||||
nsresult WillMoveNode();
|
||||
nsresult DidMoveNode(nsIDOMNode *aOldParent, PRInt32 aOldOffset, nsIDOMNode *aNewParent, PRInt32 aNewOffset);
|
||||
protected:
|
||||
nsVoidArray mArray;
|
||||
PRBool mLock;
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidReplaceContainer()
|
||||
*/
|
||||
|
||||
class nsAutoReplaceContainerSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
nsIDOMNode *mOriginalNode;
|
||||
nsIDOMNode *mNewNode;
|
||||
|
||||
public:
|
||||
nsAutoReplaceContainerSelNotify(nsRangeUpdater &aRangeUpdater, nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode) :
|
||||
mRU(aRangeUpdater)
|
||||
,mOriginalNode(aOriginalNode)
|
||||
,mNewNode(aNewNode)
|
||||
{
|
||||
mRU.WillReplaceContainer();
|
||||
}
|
||||
|
||||
~nsAutoReplaceContainerSelNotify()
|
||||
{
|
||||
mRU.DidReplaceContainer(mOriginalNode, mNewNode);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidRemoveContainer()
|
||||
*/
|
||||
|
||||
class nsAutoRemoveContainerSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
nsIDOMNode *mNode;
|
||||
nsIDOMNode *mParent;
|
||||
PRInt32 mOffset;
|
||||
PRUint32 mNodeOrigLen;
|
||||
|
||||
public:
|
||||
nsAutoRemoveContainerSelNotify(nsRangeUpdater &aRangeUpdater,
|
||||
nsIDOMNode *aNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aOffset,
|
||||
PRUint32 aNodeOrigLen) :
|
||||
mRU(aRangeUpdater)
|
||||
,mNode(aNode)
|
||||
,mParent(aParent)
|
||||
,mOffset(aOffset)
|
||||
,mNodeOrigLen(aNodeOrigLen)
|
||||
{
|
||||
mRU.WillRemoveContainer();
|
||||
}
|
||||
|
||||
~nsAutoRemoveContainerSelNotify()
|
||||
{
|
||||
mRU.DidRemoveContainer(mNode, mParent, mOffset, mNodeOrigLen);
|
||||
}
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidInsertContainer()
|
||||
*/
|
||||
|
||||
class nsAutoInsertContainerSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
|
||||
public:
|
||||
nsAutoInsertContainerSelNotify(nsRangeUpdater &aRangeUpdater) :
|
||||
mRU(aRangeUpdater)
|
||||
{
|
||||
mRU.WillInsertContainer();
|
||||
}
|
||||
|
||||
~nsAutoInsertContainerSelNotify()
|
||||
{
|
||||
mRU.DidInsertContainer();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidMoveNode()
|
||||
*/
|
||||
|
||||
class nsAutoMoveNodeSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
nsIDOMNode *mOldParent;
|
||||
nsIDOMNode *mNewParent;
|
||||
PRInt32 mOldOffset;
|
||||
PRInt32 mNewOffset;
|
||||
|
||||
public:
|
||||
nsAutoMoveNodeSelNotify(nsRangeUpdater &aRangeUpdater,
|
||||
nsIDOMNode *aOldParent,
|
||||
PRInt32 aOldOffset,
|
||||
nsIDOMNode *aNewParent,
|
||||
PRInt32 aNewOffset) :
|
||||
mRU(aRangeUpdater)
|
||||
,mOldParent(aOldParent)
|
||||
,mNewParent(aNewParent)
|
||||
,mOldOffset(aOldOffset)
|
||||
,mNewOffset(aNewOffset)
|
||||
{
|
||||
mRU.WillMoveNode();
|
||||
}
|
||||
|
||||
~nsAutoMoveNodeSelNotify()
|
||||
{
|
||||
mRU.DidMoveNode(mOldParent, mOldOffset, mNewParent, mNewOffset);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "nsEditor.h" // for gInstanceCount
|
||||
#include "nsEditorController.h" //CID
|
||||
#include "nsEditorService.h"
|
||||
#include "nsPlaintextEditor.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Define the contructor function for the objects
|
||||
@ -38,6 +39,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorShell)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorController)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsComposerController)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorService)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsPlaintextEditor)
|
||||
|
||||
#ifdef ENABLE_EDITOR_API_LOG
|
||||
#include "nsHTMLEditorLog.h"
|
||||
@ -52,6 +54,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLEditor)
|
||||
// class name.
|
||||
//
|
||||
static nsModuleComponentInfo components[] = {
|
||||
{ "Text Editor", NS_TEXTEDITOR_CID,
|
||||
"@mozilla.org/editor/texteditor;1", nsPlaintextEditorConstructor, },
|
||||
#ifdef ENABLE_EDITOR_API_LOG
|
||||
{ "HTML Editor", NS_HTMLEDITOR_CID,
|
||||
"@mozilla.org/editor/htmleditor;1", nsHTMLEditorLogConstructor, },
|
||||
|
58
editor/libeditor/build/nsTextEditorReg.cpp
Normal file
58
editor/libeditor/build/nsTextEditorReg.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
/* -*- 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.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#include "nsIGenericFactory.h"
|
||||
|
||||
#include "nsEditorCID.h"
|
||||
#include "nsEditor.h" // for gInstanceCount
|
||||
#include "nsPlaintextEditor.h"
|
||||
#include "nsEditorService.h"
|
||||
#include "nsEditorController.h" //CID
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Define the contructor function for the objects
|
||||
//
|
||||
// NOTE: This creates an instance of objects by using the default constructor
|
||||
//
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorController)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorService)
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsPlaintextEditor)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Define a table of CIDs implemented by this module along with other
|
||||
// information like the function to create an instance, contractid, and
|
||||
// class name.
|
||||
//
|
||||
static nsModuleComponentInfo components[] = {
|
||||
{ "Text Editor", NS_TEXTEDITOR_CID,
|
||||
"@mozilla.org/editor/texteditor;1", nsPlaintextEditorConstructor, },
|
||||
{ "Editor Controller", NS_EDITORCONTROLLER_CID,
|
||||
"@mozilla.org/editor/editorcontroller;1", nsEditorControllerConstructor, }
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implement the NSGetModule() exported function for your module
|
||||
// and the entire implementation of the module object.
|
||||
//
|
||||
NS_IMPL_NSGETMODULE("nsEditorModule", components)
|
1619
editor/libeditor/html/nsHTMLDataTransfer.cpp
Normal file
1619
editor/libeditor/html/nsHTMLDataTransfer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -34,6 +34,7 @@ class nsISupportsArray;
|
||||
class nsVoidArray;
|
||||
class nsIDOMElement;
|
||||
class nsIEditor;
|
||||
class nsHTMLEditor;
|
||||
|
||||
class nsHTMLEditRules : public nsIHTMLEditRules, public nsTextEditRules, public nsIEditActionListener
|
||||
{
|
||||
@ -46,7 +47,7 @@ public:
|
||||
|
||||
|
||||
// nsIEditRules methods
|
||||
NS_IMETHOD Init(nsHTMLEditor *aEditor, PRUint32 aFlags);
|
||||
NS_IMETHOD Init(nsPlaintextEditor *aEditor, PRUint32 aFlags);
|
||||
NS_IMETHOD BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection);
|
||||
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection);
|
||||
NS_IMETHOD WillDoAction(nsISelection *aSelection, nsRulesInfo *aInfo, PRBool *aCancel, PRBool *aHandled);
|
||||
@ -98,10 +99,10 @@ protected:
|
||||
nsString *outString,
|
||||
PRInt32 aMaxLength);
|
||||
nsresult WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult DidInsertBreak(nsISelection *aSelection, nsresult aResult);
|
||||
nsresult WillDeleteSelection(nsISelection *aSelection, nsIEditor::EDirection aAction,
|
||||
PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult DeleteNonTableElements(nsIDOMNode *aNode);
|
||||
|
||||
nsresult WillMakeList(nsISelection *aSelection, const nsString *aListType, PRBool aEntireList, PRBool *aCancel, PRBool *aHandled, const nsString *aItemType=nsnull);
|
||||
nsresult WillRemoveList(nsISelection *aSelection, PRBool aOrderd, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillIndent(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled);
|
||||
@ -110,17 +111,13 @@ protected:
|
||||
nsresult WillMakeDefListItem(nsISelection *aSelection, const nsString *aBlockType, PRBool aEntireList, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillMakeBasicBlock(nsISelection *aSelection, const nsString *aBlockType, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult DidMakeBasicBlock(nsISelection *aSelection, nsRulesInfo *aInfo, nsresult aResult);
|
||||
|
||||
nsresult AlignInnerBlocks(nsIDOMNode *aNode, const nsString *alignType);
|
||||
nsresult AlignBlockContents(nsIDOMNode *aNode, const nsString *alignType);
|
||||
nsresult GetInnerContent(nsIDOMNode *aNode, nsISupportsArray *outArrayOfNodes, PRBool aList = PR_TRUE, PRBool aTble = PR_TRUE);
|
||||
|
||||
nsresult InsertTab(nsISelection *aSelection, nsString *outString);
|
||||
|
||||
nsresult ReturnInHeader(nsISelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset);
|
||||
nsresult ReturnInParagraph(nsISelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult ReturnInListItem(nsISelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset);
|
||||
|
||||
nsresult AfterEditInner(PRInt32 action, nsIEditor::EDirection aDirection);
|
||||
nsresult ConvertListType(nsIDOMNode *aList, nsCOMPtr<nsIDOMNode> *outList, const nsString& aListType, const nsString& aItemType);
|
||||
nsresult CreateStyleForInsertText(nsISelection *aSelection, nsIDOMDocument *aDoc);
|
||||
@ -132,7 +129,6 @@ protected:
|
||||
PRBool IsLastNode(nsIDOMNode *aNode);
|
||||
PRBool AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock);
|
||||
PRBool AtEndOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock);
|
||||
|
||||
nsresult GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, PRInt32 aOffset,
|
||||
PRInt32 actionID, nsCOMPtr<nsIDOMNode> *outNode, PRInt32 *outOffset);
|
||||
nsresult GetPromotedRanges(nsISelection *inSelection,
|
||||
@ -154,20 +150,16 @@ protected:
|
||||
nsCOMPtr<nsIDOMNode> GetHighestInlineParent(nsIDOMNode* aNode);
|
||||
nsresult MakeTransitionList(nsISupportsArray *inArrayOfNodes,
|
||||
nsVoidArray *inTransitionArray);
|
||||
|
||||
nsresult ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsString *aBlockTag);
|
||||
nsresult MakeBlockquote(nsISupportsArray *arrayOfNodes);
|
||||
nsresult SplitAsNeeded(const nsString *aTag, nsCOMPtr<nsIDOMNode> *inOutParent, PRInt32 *inOutOffset);
|
||||
nsresult AddTerminatingBR(nsIDOMNode *aBlock);
|
||||
|
||||
nsresult JoinNodesSmart( nsIDOMNode *aNodeLeft,
|
||||
nsIDOMNode *aNodeRight,
|
||||
nsCOMPtr<nsIDOMNode> *aOutMergeParent,
|
||||
PRInt32 *aOutMergeOffset);
|
||||
|
||||
nsresult GetTopEnclosingMailCite(nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutCiteNode);
|
||||
nsresult GetTopEnclosingMailCite(nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutCiteNode, PRBool aPlaintext);
|
||||
nsresult PopListItem(nsIDOMNode *aListItem, PRBool *aOutOfList);
|
||||
|
||||
nsresult AdjustSpecialBreaks(PRBool aSafeToAskFrames = PR_FALSE);
|
||||
nsresult AdjustWhitespace(nsISelection *aSelection);
|
||||
nsresult AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection aAction);
|
||||
@ -180,14 +172,13 @@ protected:
|
||||
nsresult SelectionEndpointInNode(nsIDOMNode *aNode, PRBool *aResult);
|
||||
nsresult DoTextNodeWhitespace(nsIDOMCharacterData *aTextNode, PRInt32 aStart, PRInt32 aEnd);
|
||||
nsresult UpdateDocChangeRange(nsIDOMRange *aRange);
|
||||
|
||||
nsresult ConvertWhitespace(const nsString & inString, nsString & outString);
|
||||
nsresult ConfirmSelectionInBody();
|
||||
|
||||
nsresult InsertMozBRIfNeeded(nsIDOMNode *aNode);
|
||||
|
||||
// data members
|
||||
protected:
|
||||
nsHTMLEditor *mHTMLEditor;
|
||||
nsCOMPtr<nsIDOMRange> mDocChangeRange;
|
||||
PRBool mListenerEnabled;
|
||||
PRBool mReturnInEmptyLIKillsList;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "nsEditor.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsIDOMNodeList.h"
|
||||
#include "nsIDOMHTMLAnchorElement.h"
|
||||
|
||||
/********************************************************
|
||||
* helper methods from nsTextEditRules
|
||||
@ -487,6 +488,34 @@ nsHTMLEditUtils::IsImage(nsIDOMNode *node)
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHTMLEditUtils::IsLink(nsIDOMNode *aNode)
|
||||
{
|
||||
if (!aNode) return PR_FALSE;
|
||||
nsCOMPtr<nsIDOMHTMLAnchorElement> anchor = do_QueryInterface(aNode);
|
||||
if (anchor)
|
||||
{
|
||||
nsAutoString tmpText;
|
||||
if (NS_SUCCEEDED(anchor->GetHref(tmpText)) && tmpText.GetUnicode() && tmpText.Length() != 0)
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHTMLEditUtils::IsNamedAnchor(nsIDOMNode *aNode)
|
||||
{
|
||||
if (!aNode) return PR_FALSE;
|
||||
nsCOMPtr<nsIDOMHTMLAnchorElement> anchor = do_QueryInterface(aNode);
|
||||
if (anchor)
|
||||
{
|
||||
nsAutoString tmpText;
|
||||
if (NS_SUCCEEDED(anchor->GetName(tmpText)) && tmpText.GetUnicode() && tmpText.Length() != 0)
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// IsDiv: true if node an html div node
|
||||
|
@ -58,6 +58,8 @@ public:
|
||||
static PRBool IsAddress(nsIDOMNode *aNode);
|
||||
static PRBool IsAnchor(nsIDOMNode *aNode);
|
||||
static PRBool IsImage(nsIDOMNode *aNode);
|
||||
static PRBool IsLink(nsIDOMNode *aNode);
|
||||
static PRBool IsNamedAnchor(nsIDOMNode *aNode);
|
||||
static PRBool IsDiv(nsIDOMNode *aNode);
|
||||
static PRBool IsNormalDiv(nsIDOMNode *aNode);
|
||||
static PRBool IsMozDiv(nsIDOMNode *aNode);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,8 @@
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "nsIPlaintextEditor.h"
|
||||
#include "nsPlaintextEditor.h"
|
||||
#include "nsIEditor.h"
|
||||
#include "nsIHTMLEditor.h"
|
||||
#include "nsITableEditor.h"
|
||||
#include "nsIEditorMailSupport.h"
|
||||
@ -51,8 +52,7 @@ class nsIDocumentEncoder;
|
||||
* The HTML editor implementation.<br>
|
||||
* Use to edit HTML document represented as a DOM tree.
|
||||
*/
|
||||
class nsHTMLEditor : public nsEditor,
|
||||
public nsIPlaintextEditor,
|
||||
class nsHTMLEditor : public nsPlaintextEditor,
|
||||
public nsIHTMLEditor,
|
||||
public nsIEditorMailSupport,
|
||||
public nsITableEditor,
|
||||
@ -74,7 +74,10 @@ public:
|
||||
kOpRemoveList = 3006,
|
||||
kOpMakeDefListItem = 3007,
|
||||
kOpInsertElement = 3008,
|
||||
kOpInsertQuotation = 3009
|
||||
kOpInsertQuotation = 3009,
|
||||
kOpSetTextProperty = 3010,
|
||||
kOpRemoveTextProperty = 3011,
|
||||
kOpHTMLPaste = 3012
|
||||
};
|
||||
|
||||
|
||||
@ -89,8 +92,9 @@ public:
|
||||
nsHTMLEditor();
|
||||
virtual ~nsHTMLEditor();
|
||||
|
||||
/* ------------ nsIPlaintextEditor methods -------------- */
|
||||
NS_DECL_NSIPLAINTEXTEDITOR
|
||||
/* ------------ nsPlaintextEditor overrides -------------- */
|
||||
NS_IMETHODIMP HandleKeyPress(nsIDOMKeyEvent* aKeyEvent);
|
||||
NS_IMETHODIMP CollapseSelectionToStart();
|
||||
|
||||
/* ------------ nsIHTMLEditor methods -------------- */
|
||||
NS_IMETHOD SetInlineProperty(nsIAtom *aProperty,
|
||||
@ -118,7 +122,6 @@ public:
|
||||
NS_IMETHOD RebuildDocumentFromSource(const nsString& aSourceString);
|
||||
NS_IMETHOD InsertElementAtSelection(nsIDOMElement* aElement, PRBool aDeleteSelection);
|
||||
|
||||
NS_IMETHOD DeleteSelectionAndCreateNode(const nsString& aTag, nsIDOMNode ** aNewNode);
|
||||
NS_IMETHOD SelectElement(nsIDOMElement* aElement);
|
||||
NS_IMETHOD SetCaretAfterElement(nsIDOMElement* aElement);
|
||||
|
||||
@ -240,12 +243,6 @@ public:
|
||||
/** prepare the editor for use */
|
||||
NS_IMETHOD Init(nsIDOMDocument *aDoc, nsIPresShell *aPresShell, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags);
|
||||
|
||||
NS_IMETHOD GetDocumentIsEmpty(PRBool *aDocumentIsEmpty);
|
||||
|
||||
NS_IMETHOD DeleteSelection(EDirection aAction);
|
||||
|
||||
NS_IMETHOD SetDocumentCharacterSet(const PRUnichar* characterSet);
|
||||
|
||||
/** we override this here to install event listeners */
|
||||
NS_IMETHOD PostCreate();
|
||||
|
||||
@ -266,15 +263,6 @@ public:
|
||||
NS_IMETHOD DoDrag(nsIDOMEvent *aDragEvent);
|
||||
NS_IMETHOD InsertFromDrop(nsIDOMEvent* aDropEvent);
|
||||
|
||||
NS_IMETHOD OutputToString(nsAWritableString& aOutputString,
|
||||
const nsAReadableString& aFormatType,
|
||||
PRUint32 aFlags);
|
||||
|
||||
NS_IMETHOD OutputToStream(nsIOutputStream* aOutputStream,
|
||||
const nsAReadableString& aFormatType,
|
||||
const nsAReadableString* aCharsetOverride,
|
||||
PRUint32 aFlags);
|
||||
|
||||
NS_IMETHOD GetHeadContentsAsHTML(nsString& aOutputString);
|
||||
NS_IMETHOD ReplaceHeadContentsWithHTML(const nsString &aSourceToInsert);
|
||||
|
||||
@ -307,7 +295,6 @@ public:
|
||||
PRInt32 aOffset,
|
||||
PRBool aNoEmptyNodes);
|
||||
|
||||
NS_IMETHOD GetBodyStyleContext(nsIStyleContext** aStyleContext);
|
||||
|
||||
/** returns the absolute position of the end points of aSelection
|
||||
* in the document as a text stream.
|
||||
@ -356,8 +343,6 @@ protected:
|
||||
*/
|
||||
NS_IMETHOD GetLayoutObject(nsIDOMNode *aInNode, nsISupports **aOutLayoutObject);
|
||||
|
||||
NS_IMETHOD DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNode> &parentSelectedNode, PRInt32& offsetOfNewNode);
|
||||
|
||||
/* StyleSheet load callback */
|
||||
static void ApplyStyleSheetToPresShellDocument(nsICSSStyleSheet* aSheet, void *aData);
|
||||
|
||||
@ -376,11 +361,11 @@ protected:
|
||||
// key event helpers
|
||||
NS_IMETHOD TabInTable(PRBool inIsShift, PRBool *outHandled);
|
||||
NS_IMETHOD CreateBR(nsIDOMNode *aNode, PRInt32 aOffset,
|
||||
nsCOMPtr<nsIDOMNode> *outBRNode, EDirection aSelect = eNone);
|
||||
nsCOMPtr<nsIDOMNode> *outBRNode, nsIEditor::EDirection aSelect = nsIEditor::eNone);
|
||||
NS_IMETHOD CreateBRImpl(nsCOMPtr<nsIDOMNode> *aInOutParent,
|
||||
PRInt32 *aInOutOffset,
|
||||
nsCOMPtr<nsIDOMNode> *outBRNode,
|
||||
EDirection aSelect);
|
||||
nsIEditor::EDirection aSelect);
|
||||
NS_IMETHOD InsertBR(nsCOMPtr<nsIDOMNode> *outBRNode);
|
||||
|
||||
// Table Editing (implemented in nsTableEditor.cpp)
|
||||
@ -491,12 +476,6 @@ protected:
|
||||
PRInt32 aEndOffset,
|
||||
nsISelection *aSelection);
|
||||
|
||||
// Helpers for output routines
|
||||
NS_IMETHOD GetAndInitDocEncoder(const nsAReadableString& aFormatType,
|
||||
PRUint32 aFlags,
|
||||
const nsAReadableString* aCharset,
|
||||
nsIDocumentEncoder** encoder);
|
||||
|
||||
// Methods for handling plaintext quotations
|
||||
NS_IMETHOD PasteAsPlaintextQuotation(PRInt32 aSelectionType);
|
||||
NS_IMETHOD InsertAsPlaintextQuotation(const nsString& aQuotedText,
|
||||
@ -610,38 +589,24 @@ protected:
|
||||
// Data members
|
||||
protected:
|
||||
|
||||
TypeInState* mTypeInState;
|
||||
nsCOMPtr<nsIEditRules> mRules;
|
||||
nsCOMPtr<nsIDOMEventListener> mKeyListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mMouseListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mTextListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mCompositionListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mDragListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mFocusListenerP;
|
||||
PRBool mIsComposing;
|
||||
|
||||
// Used by nsIPlaintextEditor but not html editors -- factor me!
|
||||
PRInt32 mMaxTextLength;
|
||||
TypeInState* mTypeInState;
|
||||
|
||||
nsCOMPtr<nsIAtom> mBoldAtom;
|
||||
nsCOMPtr<nsIAtom> mItalicAtom;
|
||||
nsCOMPtr<nsIAtom> mUnderlineAtom;
|
||||
nsCOMPtr<nsIAtom> mFontAtom;
|
||||
nsCOMPtr<nsIAtom> mLinkAtom;
|
||||
nsCOMPtr<nsIAtom> mBoldAtom;
|
||||
nsCOMPtr<nsIAtom> mItalicAtom;
|
||||
nsCOMPtr<nsIAtom> mUnderlineAtom;
|
||||
nsCOMPtr<nsIAtom> mFontAtom;
|
||||
nsCOMPtr<nsIAtom> mLinkAtom;
|
||||
nsCOMPtr<nsIDOMNode> mCachedNode;
|
||||
|
||||
PRBool mCachedBoldStyle;
|
||||
PRBool mCachedItalicStyle;
|
||||
PRBool mCachedUnderlineStyle;
|
||||
PRBool mCachedBoldStyle;
|
||||
PRBool mCachedItalicStyle;
|
||||
PRBool mCachedUnderlineStyle;
|
||||
nsString mCachedFontName;
|
||||
|
||||
// Used by GetFirstSelectedCell and GetNextSelectedCell
|
||||
PRInt32 mSelectedCellIndex;
|
||||
|
||||
public:
|
||||
static nsIAtom *gTypingTxnName;
|
||||
static nsIAtom *gIMETxnName;
|
||||
static nsIAtom *gDeleteTxnName;
|
||||
|
||||
// friends
|
||||
friend class nsHTMLEditRules;
|
||||
|
1486
editor/libeditor/html/nsHTMLEditorStyle.cpp
Normal file
1486
editor/libeditor/html/nsHTMLEditorStyle.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -28,6 +28,8 @@
|
||||
0xa6cf9121, 0x15b3, 0x11d2, \
|
||||
{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} }
|
||||
|
||||
#include "nsIHTMLEditor.h"
|
||||
|
||||
class nsIHTMLEditRules : public nsISupports
|
||||
{
|
||||
public:
|
||||
|
@ -21,7 +21,7 @@
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
*/
|
||||
#include "nsEditorEventListeners.h"
|
||||
#include "nsIPlaintextEditor.h"
|
||||
#include "nsIHTMLEditor.h"
|
||||
#include "nsEditor.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsString.h"
|
||||
@ -178,8 +178,8 @@ nsTextEditorKeyListener::KeyPress(nsIDOMEvent* aKeyEvent)
|
||||
// if we are readonly or disabled, then do nothing.
|
||||
if (NS_SUCCEEDED(mEditor->GetFlags(&flags)))
|
||||
{
|
||||
if (flags & nsIHTMLEditor::eEditorReadonlyMask ||
|
||||
flags & nsIHTMLEditor::eEditorDisabledMask)
|
||||
if (flags & nsIPlaintextEditor::eEditorReadonlyMask ||
|
||||
flags & nsIPlaintextEditor::eEditorDisabledMask)
|
||||
return NS_OK;
|
||||
}
|
||||
else
|
||||
@ -246,7 +246,7 @@ nsTextEditorKeyListener::KeyPress(nsIDOMEvent* aKeyEvent)
|
||||
break;
|
||||
|
||||
case nsIDOMKeyEvent::DOM_VK_TAB:
|
||||
if ((flags & nsIHTMLEditor::eEditorSingleLineMask))
|
||||
if ((flags & nsIPlaintextEditor::eEditorSingleLineMask))
|
||||
return NS_OK; // let it be used for focus switching
|
||||
|
||||
// else we insert the tab straight through
|
||||
@ -257,9 +257,8 @@ nsTextEditorKeyListener::KeyPress(nsIDOMEvent* aKeyEvent)
|
||||
|
||||
case nsIDOMKeyEvent::DOM_VK_RETURN:
|
||||
case nsIDOMKeyEvent::DOM_VK_ENTER:
|
||||
if (!(flags & nsIHTMLEditor::eEditorSingleLineMask))
|
||||
if (!(flags & nsIPlaintextEditor::eEditorSingleLineMask))
|
||||
{
|
||||
//htmlEditor->InsertBreak();
|
||||
textEditor->HandleKeyPress(keyEvent);
|
||||
ScrollSelectionIntoView(mEditor);
|
||||
aKeyEvent->PreventDefault(); // consumed
|
||||
@ -642,8 +641,8 @@ nsTextEditorDragListener::DragOver(nsIDOMEvent* aDragEvent)
|
||||
if ( dragSession ) {
|
||||
PRUint32 flags;
|
||||
if (NS_SUCCEEDED(mEditor->GetFlags(&flags))) {
|
||||
if ((flags & nsIHTMLEditor::eEditorDisabledMask) ||
|
||||
(flags & nsIHTMLEditor::eEditorReadonlyMask)) {
|
||||
if ((flags & nsIPlaintextEditor::eEditorDisabledMask) ||
|
||||
(flags & nsIPlaintextEditor::eEditorReadonlyMask)) {
|
||||
dragSession->SetCanDrop(PR_FALSE);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1041,7 +1040,7 @@ nsTextEditorFocusListener::Focus(nsIDOMEvent* aEvent)
|
||||
PRUint32 flags;
|
||||
aEvent->PreventBubble();
|
||||
mEditor->GetFlags(&flags);
|
||||
if (! (flags & nsIHTMLEditor::eEditorDisabledMask))
|
||||
if (! (flags & nsIPlaintextEditor::eEditorDisabledMask))
|
||||
{ // only enable caret and selection if the editor is not disabled
|
||||
nsCOMPtr<nsIEditor>editor = do_QueryInterface(mEditor);
|
||||
if (editor)
|
||||
@ -1050,7 +1049,7 @@ nsTextEditorFocusListener::Focus(nsIDOMEvent* aEvent)
|
||||
editor->GetSelectionController(getter_AddRefs(selCon));
|
||||
if (selCon)
|
||||
{
|
||||
if (! (flags & nsIHTMLEditor::eEditorReadonlyMask))
|
||||
if (! (flags & nsIPlaintextEditor::eEditorReadonlyMask))
|
||||
{ // only enable caret if the editor is not readonly
|
||||
PRInt32 pixelWidth;
|
||||
nsresult result;
|
||||
@ -1059,7 +1058,7 @@ nsTextEditorFocusListener::Focus(nsIDOMEvent* aEvent)
|
||||
|
||||
if (NS_SUCCEEDED(result) && look)
|
||||
{
|
||||
if(flags & nsIHTMLEditor::eEditorSingleLineMask)
|
||||
if(flags & nsIPlaintextEditor::eEditorSingleLineMask)
|
||||
look->GetMetric(nsILookAndFeel::eMetric_SingleLineCaretWidth, pixelWidth);
|
||||
else
|
||||
look->GetMetric(nsILookAndFeel::eMetric_MultiLineCaretWidth, pixelWidth);
|
||||
@ -1109,11 +1108,11 @@ nsTextEditorFocusListener::Blur(nsIDOMEvent* aEvent)
|
||||
if (selCon)
|
||||
{
|
||||
selCon->SetCaretEnabled(PR_FALSE);
|
||||
if((flags & nsIHTMLEditor::eEditorWidgetMask) ||
|
||||
(flags & nsIHTMLEditor::eEditorPasswordMask) ||
|
||||
(flags & nsIHTMLEditor::eEditorReadonlyMask) ||
|
||||
(flags & nsIHTMLEditor::eEditorDisabledMask) ||
|
||||
(flags & nsIHTMLEditor::eEditorFilterInputMask))
|
||||
if((flags & nsIPlaintextEditor::eEditorWidgetMask) ||
|
||||
(flags & nsIPlaintextEditor::eEditorPasswordMask) ||
|
||||
(flags & nsIPlaintextEditor::eEditorReadonlyMask) ||
|
||||
(flags & nsIPlaintextEditor::eEditorDisabledMask) ||
|
||||
(flags & nsIPlaintextEditor::eEditorFilterInputMask))
|
||||
{
|
||||
selCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);//hide but do NOT turn off
|
||||
}
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include "nsIDOMFocusListener.h"
|
||||
|
||||
#include "nsIEditor.h"
|
||||
#include "nsIHTMLEditor.h"
|
||||
#include "nsIPlaintextEditor.h"
|
||||
|
||||
/** The nsTextEditorKeyListener public nsIDOMKeyListener
|
||||
* This class will delegate events to its editor according to the translation
|
||||
|
582
editor/libeditor/text/nsPlaintextDataTransfer.cpp
Normal file
582
editor/libeditor/text/nsPlaintextDataTransfer.cpp
Normal file
@ -0,0 +1,582 @@
|
||||
/* -*- 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.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
#include "nsICaret.h"
|
||||
|
||||
|
||||
#include "nsPlaintextEditor.h"
|
||||
#include "nsHTMLEditUtils.h"
|
||||
|
||||
#include "nsEditorEventListeners.h"
|
||||
|
||||
#include "nsIDOMText.h"
|
||||
#include "nsIDOMNodeList.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMAttr.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMEventReceiver.h"
|
||||
#include "nsIDOMKeyEvent.h"
|
||||
#include "nsIDOMKeyListener.h"
|
||||
#include "nsIDOMMouseListener.h"
|
||||
#include "nsIDOMMouseEvent.h"
|
||||
#include "nsISelection.h"
|
||||
#include "nsISelectionPrivate.h"
|
||||
#include "nsIDOMHTMLAnchorElement.h"
|
||||
#include "nsIDOMHTMLImageElement.h"
|
||||
#include "nsISelectionController.h"
|
||||
|
||||
#include "nsIFrameSelection.h" // For TABLESELECTION_ defines
|
||||
#include "nsIIndependentSelection.h" //domselections answer to frameselection
|
||||
|
||||
|
||||
#include "nsICSSLoader.h"
|
||||
#include "nsICSSStyleSheet.h"
|
||||
#include "nsIHTMLContentContainer.h"
|
||||
#include "nsIStyleSet.h"
|
||||
#include "nsIDocumentObserver.h"
|
||||
#include "nsIDocumentStateListener.h"
|
||||
|
||||
#include "nsIStyleContext.h"
|
||||
|
||||
#include "nsIEnumerator.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIContentIterator.h"
|
||||
#include "nsEditorCID.h"
|
||||
#include "nsLayoutCID.h"
|
||||
#include "nsIDOMRange.h"
|
||||
#include "nsIDOMNSRange.h"
|
||||
#include "nsISupportsArray.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsFileSpec.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsWidgetsCID.h"
|
||||
#include "nsIDocumentEncoder.h"
|
||||
#include "nsIDOMDocumentFragment.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsIParser.h"
|
||||
#include "nsParserCIID.h"
|
||||
#include "nsIImage.h"
|
||||
#include "nsAOLCiter.h"
|
||||
#include "nsInternetCiter.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "InsertTextTxn.h"
|
||||
|
||||
// netwerk
|
||||
#include "nsIURI.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
// Drag & Drop, Clipboard
|
||||
#include "nsWidgetsCID.h"
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsITransferable.h"
|
||||
#include "nsIDragService.h"
|
||||
#include "nsIDOMNSUIEvent.h"
|
||||
|
||||
// Transactionas
|
||||
#include "PlaceholderTxn.h"
|
||||
#include "nsStyleSheetTxns.h"
|
||||
|
||||
// Misc
|
||||
#include "TextEditorTest.h"
|
||||
#include "nsEditorUtils.h"
|
||||
#include "nsIPref.h"
|
||||
const PRUnichar nbsp = 160;
|
||||
|
||||
// HACK - CID for NS_CTRANSITIONAL_DTD_CID so that we can get at transitional dtd
|
||||
#define NS_CTRANSITIONAL_DTD_CID \
|
||||
{ 0x4611d482, 0x960a, 0x11d4, { 0x8e, 0xb0, 0xb6, 0x17, 0x66, 0x1b, 0x6f, 0x7c } }
|
||||
|
||||
|
||||
static NS_DEFINE_CID(kHTMLEditorCID, NS_HTMLEDITOR_CID);
|
||||
static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID);
|
||||
static NS_DEFINE_IID(kSubtreeIteratorCID, NS_SUBTREEITERATOR_CID);
|
||||
static NS_DEFINE_CID(kCRangeCID, NS_RANGE_CID);
|
||||
static NS_DEFINE_CID(kCDOMSelectionCID, NS_DOMSELECTION_CID);
|
||||
static NS_DEFINE_IID(kFileWidgetCID, NS_FILEWIDGET_CID);
|
||||
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
|
||||
static NS_DEFINE_IID(kCParserIID, NS_IPARSER_IID);
|
||||
static NS_DEFINE_IID(kCParserCID, NS_PARSER_IID);
|
||||
static NS_DEFINE_CID(kCTransitionalDTDCID, NS_CTRANSITIONAL_DTD_CID);
|
||||
|
||||
// Drag & Drop, Clipboard Support
|
||||
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
|
||||
static NS_DEFINE_CID(kCTransferableCID, NS_TRANSFERABLE_CID);
|
||||
static NS_DEFINE_CID(kCDragServiceCID, NS_DRAGSERVICE_CID);
|
||||
static NS_DEFINE_CID(kCHTMLFormatConverterCID, NS_HTMLFORMATCONVERTER_CID);
|
||||
// private clipboard data flavors for html copy/paste
|
||||
#define kHTMLContext "text/_moz_htmlcontext"
|
||||
#define kHTMLInfo "text/_moz_htmlinfo"
|
||||
|
||||
|
||||
#if defined(NS_DEBUG) && defined(DEBUG_buster)
|
||||
static PRBool gNoisy = PR_FALSE;
|
||||
#else
|
||||
static const PRBool gNoisy = PR_FALSE;
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP nsPlaintextEditor::PrepareTransferable(nsITransferable **transferable)
|
||||
{
|
||||
// Create generic Transferable for getting the data
|
||||
nsresult rv = nsComponentManager::CreateInstance(kCTransferableCID, nsnull,
|
||||
NS_GET_IID(nsITransferable),
|
||||
(void**)transferable);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Get the nsITransferable interface for getting the data from the clipboard
|
||||
if (transferable) (*transferable)->AddDataFlavor(kUnicodeMime);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPlaintextEditor::InsertTextFromTransferable(nsITransferable *transferable)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
char* bestFlavor = nsnull;
|
||||
nsCOMPtr<nsISupports> genericDataObj;
|
||||
PRUint32 len = 0;
|
||||
if ( NS_SUCCEEDED(transferable->GetAnyTransferData(&bestFlavor, getter_AddRefs(genericDataObj), &len)) )
|
||||
{
|
||||
nsAutoTxnsConserveSelection dontSpazMySelection(this);
|
||||
nsAutoString flavor, stuffToPaste;
|
||||
flavor.AssignWithConversion( bestFlavor ); // just so we can use flavor.Equals()
|
||||
if (flavor.EqualsWithConversion(kUnicodeMime))
|
||||
{
|
||||
nsCOMPtr<nsISupportsWString> textDataObj ( do_QueryInterface(genericDataObj) );
|
||||
if (textDataObj && len > 0)
|
||||
{
|
||||
PRUnichar* text = nsnull;
|
||||
textDataObj->ToString ( &text );
|
||||
stuffToPaste.Assign ( text, len / 2 );
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
rv = InsertText(stuffToPaste.GetUnicode());
|
||||
if (text)
|
||||
nsMemory::Free(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
nsCRT::free(bestFlavor);
|
||||
|
||||
// Try to scroll the selection into view if the paste/drop succeeded
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
if (NS_SUCCEEDED(GetSelectionController(getter_AddRefs(selCon))) && selCon)
|
||||
selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, nsISelectionController::SELECTION_FOCUS_REGION);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPlaintextEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
|
||||
{
|
||||
ForceCompositionEnd();
|
||||
|
||||
nsresult rv;
|
||||
NS_WITH_SERVICE(nsIDragService, dragService, "@mozilla.org/widget/dragservice;1", &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIDragSession> dragSession(do_QueryInterface(dragService));
|
||||
|
||||
if (!dragSession) return NS_OK;
|
||||
|
||||
// Get the nsITransferable interface for getting the data from the drop
|
||||
nsCOMPtr<nsITransferable> trans;
|
||||
rv = PrepareTransferable(getter_AddRefs(trans));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!trans) return NS_OK; // NS_ERROR_FAILURE; SHOULD WE FAIL?
|
||||
|
||||
PRUint32 numItems = 0;
|
||||
rv = dragSession->GetNumDropItems(&numItems);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Combine any deletion and drop insertion into one transaction
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
|
||||
PRUint32 i;
|
||||
PRBool doPlaceCaret = PR_TRUE;
|
||||
for (i = 0; i < numItems; ++i)
|
||||
{
|
||||
rv = dragSession->GetData(trans, i);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!trans) return NS_OK; // NS_ERROR_FAILURE; Should we fail?
|
||||
|
||||
if ( doPlaceCaret )
|
||||
{
|
||||
// check if the user pressed the key to force a copy rather than a move
|
||||
// if we run into problems here, we'll just assume the user doesn't want a copy
|
||||
PRBool userWantsCopy = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIDOMNSUIEvent> nsuiEvent (do_QueryInterface(aDropEvent));
|
||||
if (!nsuiEvent) return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aDropEvent) );
|
||||
if (mouseEvent)
|
||||
|
||||
#ifdef XP_MAC
|
||||
mouseEvent->GetAltKey(&userWantsCopy);
|
||||
#else
|
||||
mouseEvent->GetCtrlKey(&userWantsCopy);
|
||||
#endif
|
||||
// Source doc is null if source is *not* the current editor document
|
||||
nsCOMPtr<nsIDOMDocument> srcdomdoc;
|
||||
rv = dragSession->GetSourceDocument(getter_AddRefs(srcdomdoc));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Current doc is destination
|
||||
nsCOMPtr<nsIDOMDocument>destdomdoc;
|
||||
rv = GetDocument(getter_AddRefs(destdomdoc));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
rv = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!selection) return NS_ERROR_FAILURE;
|
||||
|
||||
PRBool isCollapsed;
|
||||
rv = selection->GetIsCollapsed(&isCollapsed);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Parent and offset under the mouse cursor
|
||||
nsCOMPtr<nsIDOMNode> newSelectionParent;
|
||||
PRInt32 newSelectionOffset = 0;
|
||||
rv = nsuiEvent->GetRangeParent(getter_AddRefs(newSelectionParent));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!newSelectionParent) return NS_ERROR_FAILURE;
|
||||
|
||||
rv = nsuiEvent->GetRangeOffset(&newSelectionOffset);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
/* Creating a range to store insert position because when
|
||||
we delete the selection, range gravity will make sure the insertion
|
||||
point is in the correct place */
|
||||
nsCOMPtr<nsIDOMRange> destinationRange;
|
||||
rv = CreateRange(newSelectionParent, newSelectionOffset,newSelectionParent, newSelectionOffset, getter_AddRefs(destinationRange));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
if(!destinationRange)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// We never have to delete if selection is already collapsed
|
||||
PRBool deleteSelection = PR_FALSE;
|
||||
PRBool cursorIsInSelection = PR_FALSE;
|
||||
|
||||
// Check if mouse is in the selection
|
||||
if (!isCollapsed)
|
||||
{
|
||||
PRInt32 rangeCount;
|
||||
rv = selection->GetRangeCount(&rangeCount);
|
||||
if (NS_FAILED(rv))
|
||||
return rv?rv:NS_ERROR_FAILURE;
|
||||
|
||||
for (PRInt32 j = 0; j < rangeCount; j++)
|
||||
{
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
|
||||
rv = selection->GetRangeAt(j, getter_AddRefs(range));
|
||||
if (NS_FAILED(rv) || !range)
|
||||
continue;//dont bail yet, iterate through them all
|
||||
|
||||
nsCOMPtr<nsIDOMNSRange> nsrange(do_QueryInterface(range));
|
||||
if (NS_FAILED(rv) || !nsrange)
|
||||
continue;//dont bail yet, iterate through them all
|
||||
|
||||
rv = nsrange->IsPointInRange(newSelectionParent, newSelectionOffset, &cursorIsInSelection);
|
||||
if(cursorIsInSelection)
|
||||
break;
|
||||
}
|
||||
if (cursorIsInSelection)
|
||||
{
|
||||
// Dragging within same doc can't drop on itself -- leave!
|
||||
// (We shouldn't get here - drag event shouldn't have started if over selection)
|
||||
if (srcdomdoc == destdomdoc)
|
||||
return NS_OK;
|
||||
|
||||
// Dragging from another window onto a selection
|
||||
// XXX Decision made to NOT do this,
|
||||
// note that 4.x does replace if dropped on
|
||||
//deleteSelection = PR_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are NOT over the selection
|
||||
if (srcdomdoc == destdomdoc)
|
||||
{
|
||||
// Within the same doc: delete if user doesn't want to copy
|
||||
deleteSelection = !userWantsCopy;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Different source doc: Don't delete
|
||||
deleteSelection = PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deleteSelection)
|
||||
{
|
||||
rv = DeleteSelection(eNone);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// If we deleted the selection because we dropped from another doc,
|
||||
// then we don't have to relocate the caret (insert at the deletion point)
|
||||
if (!(deleteSelection && srcdomdoc != destdomdoc))
|
||||
{
|
||||
// Move the selection to the point under the mouse cursor
|
||||
rv = destinationRange->GetStartContainer(getter_AddRefs(newSelectionParent));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
if(!newSelectionParent)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
rv = destinationRange->GetStartOffset(&newSelectionOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
selection->Collapse(newSelectionParent, newSelectionOffset);
|
||||
}
|
||||
// We have to figure out whether to delete and relocate caret only once
|
||||
doPlaceCaret = PR_FALSE;
|
||||
}
|
||||
|
||||
rv = InsertTextFromTransferable(trans);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPlaintextEditor::CanDrag(nsIDOMEvent *aDragEvent, PRBool &aCanDrag)
|
||||
{
|
||||
/* we really should be checking the XY coordinates of the mouseevent and ensure that
|
||||
* that particular point is actually within the selection (not just that there is a selection)
|
||||
*/
|
||||
aCanDrag = PR_FALSE;
|
||||
|
||||
// KLUDGE to work around bug 50703
|
||||
// After double click and object property editing,
|
||||
// we get a spurious drag event
|
||||
if (mIgnoreSpuriousDragEvent)
|
||||
{
|
||||
mIgnoreSpuriousDragEvent = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
nsresult res = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
PRBool isCollapsed;
|
||||
res = selection->GetIsCollapsed(&isCollapsed);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// if we are collapsed, we have no selection so nothing to drag
|
||||
if ( isCollapsed )
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> eventTarget;
|
||||
res = aDragEvent->GetOriginalTarget(getter_AddRefs(eventTarget));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if ( eventTarget )
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> eventTargetDomNode = do_QueryInterface(eventTarget);
|
||||
if ( eventTargetDomNode )
|
||||
{
|
||||
PRBool amTargettedCorrectly = PR_FALSE;
|
||||
res = selection->ContainsNode(eventTargetDomNode, PR_FALSE, &amTargettedCorrectly);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
aCanDrag = amTargettedCorrectly;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPlaintextEditor::DoDrag(nsIDOMEvent *aDragEvent)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> eventTarget;
|
||||
rv = aDragEvent->GetTarget(getter_AddRefs(eventTarget));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
nsCOMPtr<nsIDOMNode> domnode = do_QueryInterface(eventTarget);
|
||||
|
||||
/* get the selection to be dragged */
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
rv = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
/* create an array of transferables */
|
||||
nsCOMPtr<nsISupportsArray> transferableArray;
|
||||
NS_NewISupportsArray(getter_AddRefs(transferableArray));
|
||||
if (transferableArray == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
/* get the drag service */
|
||||
NS_WITH_SERVICE(nsIDragService, dragService, "@mozilla.org/widget/dragservice;1", &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
/* create html flavor transferable */
|
||||
nsCOMPtr<nsITransferable> trans;
|
||||
rv = nsComponentManager::CreateInstance(kCTransferableCID, nsnull,
|
||||
NS_GET_IID(nsITransferable),
|
||||
getter_AddRefs(trans));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if ( !trans ) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> domdoc;
|
||||
rv = GetDocument(getter_AddRefs(domdoc));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
|
||||
if (doc)
|
||||
{
|
||||
nsCOMPtr<nsIDocumentEncoder> docEncoder;
|
||||
|
||||
docEncoder = do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "text/html");
|
||||
NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE);
|
||||
|
||||
docEncoder->Init(doc, NS_LITERAL_STRING("text/html"), 0);
|
||||
docEncoder->SetSelection(selection);
|
||||
|
||||
nsAutoString buffer;
|
||||
|
||||
rv = docEncoder->EncodeToString(buffer);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if ( !buffer.IsEmpty() )
|
||||
{
|
||||
nsCOMPtr<nsIFormatConverter> htmlConverter;
|
||||
rv = nsComponentManager::CreateInstance(kCHTMLFormatConverterCID, nsnull, NS_GET_IID(nsIFormatConverter),
|
||||
getter_AddRefs(htmlConverter));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!htmlConverter) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsCOMPtr<nsISupportsWString> dataWrapper;
|
||||
rv = nsComponentManager::CreateInstance(NS_SUPPORTS_WSTRING_CONTRACTID, nsnull,
|
||||
NS_GET_IID(nsISupportsWString), getter_AddRefs(dataWrapper));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if ( !dataWrapper ) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
rv = trans->AddDataFlavor(kHTMLMime);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = trans->SetConverter(htmlConverter);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = dataWrapper->SetData( NS_CONST_CAST(PRUnichar*, buffer.GetUnicode()) );
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// QI the data object an |nsISupports| so that when the transferable holds
|
||||
// onto it, it will addref the correct interface.
|
||||
nsCOMPtr<nsISupports> nsisupportsDataWrapper ( do_QueryInterface(dataWrapper) );
|
||||
rv = trans->SetTransferData(kHTMLMime, nsisupportsDataWrapper, buffer.Length() * 2);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
/* add the transferable to the array */
|
||||
rv = transferableArray->AppendElement(trans);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
/* invoke drag */
|
||||
unsigned int flags;
|
||||
// in some cases we'll want to cut rather than copy... hmmmmm...
|
||||
// if ( wantToCut )
|
||||
// flags = nsIDragService.DRAGDROP_ACTION_COPY + nsIDragService.DRAGDROP_ACTION_MOVE;
|
||||
// else
|
||||
flags = nsIDragService::DRAGDROP_ACTION_COPY + nsIDragService::DRAGDROP_ACTION_MOVE;
|
||||
|
||||
rv = dragService->InvokeDragSession( domnode, transferableArray, nsnull, flags);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
aDragEvent->PreventBubble();
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPlaintextEditor::Paste(PRInt32 aSelectionType)
|
||||
{
|
||||
ForceCompositionEnd();
|
||||
|
||||
// Get Clipboard Service
|
||||
nsresult rv;
|
||||
NS_WITH_SERVICE ( nsIClipboard, clipboard, kCClipboardCID, &rv );
|
||||
if ( NS_FAILED(rv) )
|
||||
return rv;
|
||||
|
||||
// Get the nsITransferable interface for getting the data from the clipboard
|
||||
nsCOMPtr<nsITransferable> trans;
|
||||
rv = PrepareTransferable(getter_AddRefs(trans));
|
||||
if (NS_SUCCEEDED(rv) && trans)
|
||||
{
|
||||
// Get the Data from the clipboard
|
||||
if (NS_SUCCEEDED(clipboard->GetData(trans, aSelectionType)) && IsModifiable())
|
||||
{
|
||||
rv = InsertTextFromTransferable(trans);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsPlaintextEditor::CanPaste(PRInt32 aSelectionType, PRBool &aCanPaste)
|
||||
{
|
||||
aCanPaste = PR_FALSE;
|
||||
|
||||
nsresult rv;
|
||||
NS_WITH_SERVICE(nsIClipboard, clipboard, kCClipboardCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// the flavors that we can deal with
|
||||
char* textEditorFlavors[] = { kUnicodeMime, nsnull };
|
||||
|
||||
nsCOMPtr<nsISupportsArray> flavorsList;
|
||||
rv = nsComponentManager::CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, nsnull,
|
||||
NS_GET_IID(nsISupportsArray), getter_AddRefs(flavorsList));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRUint32 editorFlags;
|
||||
GetFlags(&editorFlags);
|
||||
|
||||
// add the flavors for text editors
|
||||
for (char** flavor = textEditorFlavors; *flavor; flavor++)
|
||||
{
|
||||
nsCOMPtr<nsISupportsString> flavorString;
|
||||
nsComponentManager::CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, nsnull,
|
||||
NS_GET_IID(nsISupportsString), getter_AddRefs(flavorString));
|
||||
if (flavorString)
|
||||
{
|
||||
flavorString->SetData(*flavor);
|
||||
flavorsList->AppendElement(flavorString);
|
||||
}
|
||||
}
|
||||
|
||||
PRBool haveFlavors;
|
||||
rv = clipboard->HasDataMatchingFlavors(flavorsList, aSelectionType, &haveFlavors);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
aCanPaste = haveFlavors;
|
||||
return NS_OK;
|
||||
}
|
1808
editor/libeditor/text/nsPlaintextEditor.cpp
Normal file
1808
editor/libeditor/text/nsPlaintextEditor.cpp
Normal file
File diff suppressed because it is too large
Load Diff
228
editor/libeditor/text/nsPlaintextEditor.h
Normal file
228
editor/libeditor/text/nsPlaintextEditor.h
Normal file
@ -0,0 +1,228 @@
|
||||
/* -*- 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.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#ifndef nsPlaintextEditor_h__
|
||||
#define nsPlaintextEditor_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "nsIPlaintextEditor.h"
|
||||
|
||||
#include "nsEditor.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
|
||||
#include "TypeInState.h"
|
||||
#include "nsEditRules.h"
|
||||
|
||||
class nsIDOMKeyEvent;
|
||||
class nsITransferable;
|
||||
class nsIDOMEventReceiver;
|
||||
class nsIDocumentEncoder;
|
||||
|
||||
/**
|
||||
* The text editor implementation.
|
||||
* Use to edit text document represented as a DOM tree.
|
||||
*/
|
||||
class nsPlaintextEditor : public nsEditor,
|
||||
public nsIPlaintextEditor
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// Interfaces for addref and release and queryinterface
|
||||
// NOTE macro used is for classes that inherit from
|
||||
// another class. Only the base class should use NS_DECL_ISUPPORTS
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
/* below used by TypedText() */
|
||||
enum {
|
||||
eTypedText, /* user typed text */
|
||||
eTypedBR, /* user typed shift-enter to get a br */
|
||||
eTypedBreak /* user typed enter */
|
||||
};
|
||||
|
||||
nsPlaintextEditor();
|
||||
virtual ~nsPlaintextEditor();
|
||||
|
||||
/* ------------ nsIPlaintextEditor methods -------------- */
|
||||
NS_DECL_NSIPLAINTEXTEDITOR
|
||||
|
||||
/* ------------ nsIEditorIMESupport overrides -------------- */
|
||||
|
||||
NS_IMETHOD SetCompositionString(const nsString& aCompositionString, nsIPrivateTextRangeList* aTextRangeList,nsTextEventReply* aReply);
|
||||
NS_IMETHOD GetReconversionString(nsReconversionEventReply* aReply);
|
||||
|
||||
/* ------------ Overrides of nsEditor interface methods -------------- */
|
||||
|
||||
/** prepare the editor for use */
|
||||
NS_IMETHOD Init(nsIDOMDocument *aDoc, nsIPresShell *aPresShell, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags);
|
||||
|
||||
NS_IMETHOD GetDocumentIsEmpty(PRBool *aDocumentIsEmpty);
|
||||
|
||||
NS_IMETHOD DeleteSelection(EDirection aAction);
|
||||
|
||||
NS_IMETHOD SetDocumentCharacterSet(const PRUnichar* characterSet);
|
||||
|
||||
/** we override this here to install event listeners */
|
||||
NS_IMETHOD PostCreate();
|
||||
|
||||
NS_IMETHOD GetFlags(PRUint32 *aFlags);
|
||||
NS_IMETHOD SetFlags(PRUint32 aFlags);
|
||||
|
||||
NS_IMETHOD Undo(PRUint32 aCount);
|
||||
NS_IMETHOD Redo(PRUint32 aCount);
|
||||
|
||||
NS_IMETHOD Cut();
|
||||
NS_IMETHOD CanCut(PRBool &aCanCut);
|
||||
NS_IMETHOD Copy();
|
||||
NS_IMETHOD CanCopy(PRBool &aCanCopy);
|
||||
NS_IMETHOD Paste(PRInt32 aSelectionType);
|
||||
NS_IMETHOD CanPaste(PRInt32 aSelectionType, PRBool &aCanPaste);
|
||||
|
||||
NS_IMETHOD CanDrag(nsIDOMEvent *aDragEvent, PRBool &aCanDrag);
|
||||
NS_IMETHOD DoDrag(nsIDOMEvent *aDragEvent);
|
||||
NS_IMETHOD InsertFromDrop(nsIDOMEvent* aDropEvent);
|
||||
|
||||
NS_IMETHOD OutputToString(nsAWritableString& aOutputString,
|
||||
const nsAReadableString& aFormatType,
|
||||
PRUint32 aFlags);
|
||||
|
||||
NS_IMETHOD OutputToStream(nsIOutputStream* aOutputStream,
|
||||
const nsAReadableString& aFormatType,
|
||||
const nsAReadableString* aCharsetOverride,
|
||||
PRUint32 aFlags);
|
||||
|
||||
|
||||
/** All editor operations which alter the doc should be prefaced
|
||||
* with a call to StartOperation, naming the action and direction */
|
||||
NS_IMETHOD StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
|
||||
|
||||
/** All editor operations which alter the doc should be followed
|
||||
* with a call to EndOperation */
|
||||
NS_IMETHOD EndOperation();
|
||||
|
||||
/** make the given selection span the entire document */
|
||||
NS_IMETHOD SelectEntireDocument(nsISelection *aSelection);
|
||||
|
||||
/* ------------ Utility Routines, not part of public API -------------- */
|
||||
NS_IMETHOD TypedText(const PRUnichar* aString, PRInt32 aAction);
|
||||
|
||||
/** returns the absolute position of the end points of aSelection
|
||||
* in the document as a text stream.
|
||||
*/
|
||||
nsresult GetTextSelectionOffsets(nsISelection *aSelection,
|
||||
PRInt32 &aStartOffset,
|
||||
PRInt32 &aEndOffset);
|
||||
|
||||
nsresult GetAbsoluteOffsetsForPoints(nsIDOMNode *aInStartNode,
|
||||
PRInt32 aInStartOffset,
|
||||
nsIDOMNode *aInEndNode,
|
||||
PRInt32 aInEndOffset,
|
||||
nsIDOMNode *aInCommonParentNode,
|
||||
PRInt32 &aOutStartOffset,
|
||||
PRInt32 &aEndOffset);
|
||||
|
||||
protected:
|
||||
|
||||
NS_IMETHOD InitRules();
|
||||
void BeginEditorInit();
|
||||
nsresult EndEditorInit();
|
||||
|
||||
/** install the event listeners for the editor
|
||||
* used to be part of Init, but now broken out into a separate method
|
||||
* called by PostCreate, giving the caller the chance to interpose
|
||||
* their own listeners before we install our own backstops.
|
||||
*/
|
||||
NS_IMETHOD InstallEventListeners();
|
||||
|
||||
/** returns the layout object (nsIFrame in the real world) for aNode
|
||||
* @param aNode the content to get a frame for
|
||||
* @param aLayoutObject the "primary frame" for aNode, if one exists. May be null
|
||||
* @return NS_OK whether a frame is found or not
|
||||
* an error if some serious error occurs
|
||||
*/
|
||||
NS_IMETHOD GetLayoutObject(nsIDOMNode *aInNode, nsISupports **aOutLayoutObject);
|
||||
NS_IMETHOD GetBodyStyleContext(nsIStyleContext** aStyleContext);
|
||||
|
||||
// Helpers for output routines
|
||||
NS_IMETHOD GetAndInitDocEncoder(const nsAReadableString& aFormatType,
|
||||
PRUint32 aFlags,
|
||||
const nsAReadableString* aCharset,
|
||||
nsIDocumentEncoder** encoder);
|
||||
|
||||
// key event helpers
|
||||
NS_IMETHOD CreateBR(nsIDOMNode *aNode, PRInt32 aOffset,
|
||||
nsCOMPtr<nsIDOMNode> *outBRNode, EDirection aSelect = eNone);
|
||||
NS_IMETHOD CreateBRImpl(nsCOMPtr<nsIDOMNode> *aInOutParent,
|
||||
PRInt32 *aInOutOffset,
|
||||
nsCOMPtr<nsIDOMNode> *outBRNode,
|
||||
EDirection aSelect);
|
||||
NS_IMETHOD InsertBR(nsCOMPtr<nsIDOMNode> *outBRNode);
|
||||
|
||||
NS_IMETHOD IsRootTag(nsString &aTag, PRBool &aIsTag);
|
||||
|
||||
|
||||
// factored methods for handling insertion of data from transferables (drag&drop or clipboard)
|
||||
NS_IMETHOD PrepareTransferable(nsITransferable **transferable);
|
||||
NS_IMETHOD InsertTextFromTransferable(nsITransferable *transferable);
|
||||
|
||||
/** simple utility to handle any error with event listener allocation or registration */
|
||||
void HandleEventListenerError();
|
||||
|
||||
/* small utility routine to test the eEditorReadonly bit */
|
||||
PRBool IsModifiable();
|
||||
|
||||
nsresult GetDOMEventReceiver(nsIDOMEventReceiver **aEventReceiver);
|
||||
|
||||
//XXX Kludge: Used to suppress spurious drag/drop events (bug 50703)
|
||||
PRBool mIgnoreSpuriousDragEvent;
|
||||
NS_IMETHOD IgnoreSpuriousDragEvent(PRBool aIgnoreSpuriousDragEvent) {mIgnoreSpuriousDragEvent = aIgnoreSpuriousDragEvent; return NS_OK;}
|
||||
|
||||
// Data members
|
||||
protected:
|
||||
|
||||
nsCOMPtr<nsIEditRules> mRules;
|
||||
nsCOMPtr<nsIDOMEventListener> mKeyListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mMouseListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mTextListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mCompositionListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mDragListenerP;
|
||||
nsCOMPtr<nsIDOMEventListener> mFocusListenerP;
|
||||
PRBool mIsComposing;
|
||||
PRInt32 mMaxTextLength;
|
||||
PRInt32 mInitTriggerCounter;
|
||||
|
||||
public:
|
||||
static nsIAtom *gTypingTxnName;
|
||||
static nsIAtom *gIMETxnName;
|
||||
static nsIAtom *gDeleteTxnName;
|
||||
|
||||
// friends
|
||||
friend class nsHTMLEditRules;
|
||||
friend class nsTextEditRules;
|
||||
friend class nsAutoEditInitRulesTrigger;
|
||||
|
||||
};
|
||||
|
||||
#endif //nsPlaintextEditor_h__
|
||||
|
@ -48,7 +48,7 @@ static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
|
||||
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
|
||||
|
||||
#define CANCEL_OPERATION_IF_READONLY_OR_DISABLED \
|
||||
if ((mFlags & nsIHTMLEditor::eEditorReadonlyMask) || (mFlags & nsIHTMLEditor::eEditorDisabledMask)) \
|
||||
if ((mFlags & nsIPlaintextEditor::eEditorReadonlyMask) || (mFlags & nsIPlaintextEditor::eEditorDisabledMask)) \
|
||||
{ \
|
||||
*aCancel = PR_TRUE; \
|
||||
return NS_OK; \
|
||||
@ -101,7 +101,7 @@ NS_IMPL_QUERY_INTERFACE1(nsTextEditRules, nsIEditRules)
|
||||
********************************************************/
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTextEditRules::Init(nsHTMLEditor *aEditor, PRUint32 aFlags)
|
||||
nsTextEditRules::Init(nsPlaintextEditor *aEditor, PRUint32 aFlags)
|
||||
{
|
||||
if (!aEditor) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
@ -125,10 +125,8 @@ nsTextEditRules::Init(nsHTMLEditor *aEditor, PRUint32 aFlags)
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// create a range that is the entire body contents
|
||||
nsCOMPtr<nsIDOMRange> wholeDoc;
|
||||
res = nsComponentManager::CreateInstance(kRangeCID, nsnull, NS_GET_IID(nsIDOMRange),
|
||||
getter_AddRefs(wholeDoc));
|
||||
if (NS_FAILED(res)) return res;
|
||||
nsCOMPtr<nsIDOMRange> wholeDoc = do_CreateInstance(kRangeCID);
|
||||
if (!wholeDoc) return NS_ERROR_NULL_POINTER;
|
||||
wholeDoc->SetStart(mBody,0);
|
||||
nsCOMPtr<nsIDOMNodeList> list;
|
||||
res = mBody->GetChildNodes(getter_AddRefs(list));
|
||||
@ -163,11 +161,9 @@ nsTextEditRules::SetFlags(PRUint32 aFlags)
|
||||
// SetFlags() is really meant to only be called once
|
||||
// and at editor init time.
|
||||
|
||||
PRBool willBePlaintext = (aFlags & nsIHTMLEditor::eEditorPlaintextMask) != 0;
|
||||
PRBool alreadyPlaintext = (mFlags & nsIHTMLEditor::eEditorPlaintextMask) != 0;
|
||||
|
||||
PRBool willBePlaintext = (aFlags & nsIPlaintextEditor::eEditorPlaintextMask) != 0;
|
||||
PRBool alreadyPlaintext = (mFlags & nsIPlaintextEditor::eEditorPlaintextMask) != 0;
|
||||
mFlags = aFlags;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -207,8 +203,6 @@ nsTextEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
||||
res = CreateBogusNodeIfNeeded(selection);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// create moz-br and adjust selection if needed
|
||||
res = AdjustSelection(selection, aDirection);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@ -340,42 +334,7 @@ nsTextEditRules::WillInsert(nsISelection *aSelection, PRBool *aCancel)
|
||||
mBogusNode = do_QueryInterface(nsnull);
|
||||
}
|
||||
|
||||
// this next only works for collapsed selections right now,
|
||||
// because selection is a pain to work with when not collapsed.
|
||||
// (no good way to extend start or end of selection)
|
||||
PRBool bCollapsed;
|
||||
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!bCollapsed) return NS_OK;
|
||||
|
||||
// if we are after a mozBR in the same block, then move selection
|
||||
// to be before it
|
||||
nsCOMPtr<nsIDOMNode> selNode, priorNode;
|
||||
PRInt32 selOffset;
|
||||
// get the (collapsed) selection location
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// get prior node
|
||||
res = mEditor->GetPriorHTMLNode(selNode, selOffset, address_of(priorNode));
|
||||
if (NS_SUCCEEDED(res) && priorNode && nsHTMLEditUtils::IsMozBR(priorNode))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> block1, block2;
|
||||
if (mEditor->IsBlockNode(selNode)) block1 = selNode;
|
||||
else block1 = mEditor->GetBlockNodeParent(selNode);
|
||||
block2 = mEditor->GetBlockNodeParent(priorNode);
|
||||
|
||||
if (block1 != block2) return NS_OK;
|
||||
|
||||
// if we are here then the selection is right after a mozBR
|
||||
// that is in the same block as the selection. We need to move
|
||||
// the selection start to be before the mozBR.
|
||||
res = nsEditor::GetNodeLocation(priorNode, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = aSelection->Collapse(selNode,selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
return res;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -384,44 +343,13 @@ nsTextEditRules::DidInsert(nsISelection *aSelection, nsresult aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::GetTopEnclosingPre(nsIDOMNode *aNode,
|
||||
nsIDOMNode** aOutPreNode)
|
||||
{
|
||||
// check parms
|
||||
if (!aNode || !aOutPreNode)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
*aOutPreNode = 0;
|
||||
|
||||
nsresult res = NS_OK;
|
||||
nsCOMPtr<nsIDOMNode> node, parentNode;
|
||||
node = do_QueryInterface(aNode);
|
||||
|
||||
while (node)
|
||||
{
|
||||
nsAutoString tag;
|
||||
nsEditor::GetTagString(node, tag);
|
||||
if (tag.EqualsWithConversion("pre", PR_TRUE))
|
||||
*aOutPreNode = node;
|
||||
else if (tag.EqualsWithConversion("body", PR_TRUE))
|
||||
break;
|
||||
|
||||
res = node->GetParentNode(getter_AddRefs(parentNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
node = parentNode;
|
||||
}
|
||||
|
||||
NS_IF_ADDREF(*aOutPreNode);
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled)
|
||||
{
|
||||
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
||||
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
|
||||
*aHandled = PR_FALSE;
|
||||
if (mFlags & nsIHTMLEditor::eEditorSingleLineMask) {
|
||||
if (mFlags & nsIPlaintextEditor::eEditorSingleLineMask) {
|
||||
*aCancel = PR_TRUE;
|
||||
}
|
||||
else
|
||||
@ -444,72 +372,6 @@ nsTextEditRules::WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBo
|
||||
// we want to ignore result of WillInsert()
|
||||
*aCancel = PR_FALSE;
|
||||
|
||||
// Mail rule: split any <pre> tags in the way,
|
||||
// since they're probably quoted text.
|
||||
// For now, do this for all plaintext since mail is our main customer
|
||||
// and we don't currently set eEditorMailMask for plaintext mail.
|
||||
if (mTheAction != nsHTMLEditor::kOpInsertQuotation) // && mFlags & nsIHTMLEditor::eEditorMailMask)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> preNode, selNode;
|
||||
PRInt32 selOffset, newOffset;
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// If any of the following fail, then just proceed with the
|
||||
// normal break insertion without worrying about the error
|
||||
res = GetTopEnclosingPre(selNode, getter_AddRefs(preNode));
|
||||
if (NS_SUCCEEDED(res) && preNode)
|
||||
{
|
||||
// Only split quote nodes: see if it has the attribute _moz_quote
|
||||
nsCOMPtr<nsIDOMElement> preElement (do_QueryInterface(preNode));
|
||||
if (preElement)
|
||||
{
|
||||
nsString mozQuote; mozQuote.AssignWithConversion("_moz_quote");
|
||||
nsString mozQuoteVal;
|
||||
PRBool isMozQuote = PR_FALSE;
|
||||
if (NS_SUCCEEDED(mEditor->GetAttributeValue(preElement, mozQuote,
|
||||
mozQuoteVal, isMozQuote))
|
||||
&& isMozQuote)
|
||||
{
|
||||
printf("It's a moz quote -- splitting\n");
|
||||
nsCOMPtr<nsIDOMNode> outLeftNode;
|
||||
nsCOMPtr<nsIDOMNode> outRightNode;
|
||||
res = mEditor->SplitNodeDeep(preNode, selNode, selOffset, &newOffset, PR_TRUE, address_of(outLeftNode), address_of(outRightNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
PRBool bIsEmptyNode;
|
||||
|
||||
// rememeber parent of selNode now, since we might delete selNode below
|
||||
res = preNode->GetParentNode(getter_AddRefs(selNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
if (outLeftNode)
|
||||
{
|
||||
res = mEditor->IsEmptyNode(outLeftNode, &bIsEmptyNode, PR_TRUE, PR_FALSE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (bIsEmptyNode) mEditor->DeleteNode(outLeftNode);
|
||||
}
|
||||
if (outRightNode)
|
||||
{
|
||||
// HACK alert: consume a br if there is one at front of node
|
||||
nsCOMPtr<nsIDOMNode> firstNode;
|
||||
res = mEditor->GetFirstEditableNode(outRightNode, address_of(firstNode));
|
||||
if (firstNode && nsHTMLEditUtils::IsBreak(firstNode))
|
||||
{
|
||||
mEditor->DeleteNode(firstNode);
|
||||
}
|
||||
|
||||
res = mEditor->IsEmptyNode(outRightNode, &bIsEmptyNode, PR_TRUE, PR_FALSE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (bIsEmptyNode) mEditor->DeleteNode(outRightNode);
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
// last ePrevious param causes selection to be set before the break
|
||||
res = mEditor->CreateBR(selNode, newOffset, address_of(brNode), nsIEditor::ePrevious);
|
||||
*aHandled = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -519,42 +381,44 @@ nsTextEditRules::DidInsertBreak(nsISelection *aSelection, nsresult aResult)
|
||||
{
|
||||
// we only need to execute the stuff below if we are a plaintext editor.
|
||||
// html editors have a different mechanism for putting in mozBR's
|
||||
// (because there are a bunch more placesyou have to worry about it in html)
|
||||
if (!nsIHTMLEditor::eEditorPlaintextMask & mFlags) return NS_OK;
|
||||
// (because there are a bunch more places you have to worry about it in html)
|
||||
if (!nsIPlaintextEditor::eEditorPlaintextMask & mFlags) return NS_OK;
|
||||
|
||||
// if we are at the end of the document, we need to insert
|
||||
// a special mozBR following the normal br, and then set the
|
||||
// selection to stick to the mozBR.
|
||||
PRInt32 selOffset;
|
||||
nsCOMPtr<nsIDOMNode> nearNode, selNode;
|
||||
nsCOMPtr<nsIDOMNode> nearNode, selNode, root, temp;
|
||||
nsCOMPtr<nsIDOMElement> rootElem;
|
||||
nsresult res;
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->GetPriorHTMLNode(selNode, selOffset, address_of(nearNode));
|
||||
// confirm we are at end of document
|
||||
if (selOffset == 0) return NS_OK; // cant be after a br if we are at offset 0
|
||||
res = mEditor->GetRootElement(getter_AddRefs(rootElem));
|
||||
if (NS_FAILED(res)) return res;
|
||||
root = do_QueryInterface(rootElem);
|
||||
if (!root) return NS_ERROR_NULL_POINTER;
|
||||
if (selNode != root) return NS_OK; // must be inside text node or somewhere other than end of root
|
||||
temp = mEditor->GetChildAt(selNode, selOffset);
|
||||
if (temp) return NS_OK; // cant be at end of there is a node after us.
|
||||
nearNode = mEditor->GetChildAt(selNode, selOffset-1);
|
||||
if (nearNode && nsHTMLEditUtils::IsBreak(nearNode) && !nsHTMLEditUtils::IsMozBR(nearNode))
|
||||
{
|
||||
PRBool bIsLast;
|
||||
res = mEditor->IsLastEditableChild(nearNode, &bIsLast);
|
||||
nsCOMPtr<nsISelection> sel(aSelection);
|
||||
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(sel));
|
||||
// need to insert special moz BR. Why? Because if we don't
|
||||
// the user will see no new line for the break. Also, things
|
||||
// like table cells won't grow in height.
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
res = CreateMozBR(selNode, selOffset, address_of(brNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = nsEditor::GetNodeLocation(brNode, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
selPrivate->SetInterlinePosition(PR_TRUE);
|
||||
res = aSelection->Collapse(selNode,selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (bIsLast)
|
||||
{
|
||||
nsCOMPtr<nsISelection> sel(aSelection);
|
||||
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(sel));
|
||||
// need to insert special moz BR. Why? Because if we don't
|
||||
// the user will see no new line for the break. Also, things
|
||||
// like table cells won't grow in height.
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
res = CreateMozBR(selNode, selOffset, address_of(brNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = nsEditor::GetNodeLocation(brNode, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
selPrivate->SetInterlinePosition(PR_TRUE);
|
||||
res = aSelection->Collapse(selNode,selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
// mEditor->DumpContentTree();
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -595,7 +459,7 @@ nsTextEditRules::WillInsertText(PRInt32 aAction,
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// handle password field docs
|
||||
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
||||
if (mFlags & nsIPlaintextEditor::eEditorPasswordMask)
|
||||
{
|
||||
res = mEditor->GetTextSelectionOffsets(aSelection, start, end);
|
||||
NS_ASSERTION((NS_SUCCEEDED(res)), "getTextSelectionOffsets failed!");
|
||||
@ -621,7 +485,7 @@ nsTextEditRules::WillInsertText(PRInt32 aAction,
|
||||
// handle password field data
|
||||
// this has the side effect of changing all the characters in aOutString
|
||||
// to the replacement character
|
||||
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
||||
if (mFlags & nsIPlaintextEditor::eEditorPasswordMask)
|
||||
{
|
||||
res = EchoInsertionToPWBuff(start, end, outString);
|
||||
if (NS_FAILED(res)) return res;
|
||||
@ -646,7 +510,7 @@ nsTextEditRules::WillInsertText(PRInt32 aAction,
|
||||
rv = prefs->GetIntPref("editor.singleLine.pasteNewlines",
|
||||
&singleLineNewlineBehavior);
|
||||
|
||||
if (nsIHTMLEditor::eEditorSingleLineMask & mFlags)
|
||||
if (nsIPlaintextEditor::eEditorSingleLineMask & mFlags)
|
||||
{
|
||||
if (singleLineNewlineBehavior == eReplaceWithSpaces)
|
||||
outString->ReplaceChar(CRLF, ' ');
|
||||
@ -731,7 +595,7 @@ nsTextEditRules::WillInsertText(PRInt32 aAction,
|
||||
// is it a return?
|
||||
if (subStr.EqualsWithConversion("\n"))
|
||||
{
|
||||
if (nsIHTMLEditor::eEditorSingleLineMask & mFlags)
|
||||
if (nsIPlaintextEditor::eEditorSingleLineMask & mFlags)
|
||||
{
|
||||
NS_ASSERTION((singleLineNewlineBehavior == ePasteIntact),
|
||||
"Newline improperly getting into single-line edit field!");
|
||||
@ -814,7 +678,7 @@ nsTextEditRules::WillSetTextProperty(nsISelection *aSelection, PRBool *aCancel,
|
||||
nsresult res = NS_OK;
|
||||
|
||||
// XXX: should probably return a success value other than NS_OK that means "not allowed"
|
||||
if (nsIHTMLEditor::eEditorPlaintextMask & mFlags) {
|
||||
if (nsIPlaintextEditor::eEditorPlaintextMask & mFlags) {
|
||||
*aCancel = PR_TRUE;
|
||||
}
|
||||
return res;
|
||||
@ -834,7 +698,7 @@ nsTextEditRules::WillRemoveTextProperty(nsISelection *aSelection, PRBool *aCance
|
||||
nsresult res = NS_OK;
|
||||
|
||||
// XXX: should probably return a success value other than NS_OK that means "not allowed"
|
||||
if (nsIHTMLEditor::eEditorPlaintextMask & mFlags) {
|
||||
if (nsIPlaintextEditor::eEditorPlaintextMask & mFlags) {
|
||||
*aCancel = PR_TRUE;
|
||||
}
|
||||
return res;
|
||||
@ -864,7 +728,7 @@ nsTextEditRules::WillDeleteSelection(nsISelection *aSelection,
|
||||
*aCancel = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
||||
if (mFlags & nsIPlaintextEditor::eEditorPasswordMask)
|
||||
{
|
||||
// manage the password buffer
|
||||
PRInt32 start, end;
|
||||
@ -1098,7 +962,7 @@ nsTextEditRules::WillOutputText(nsISelection *aSelection,
|
||||
|
||||
if (PR_TRUE == aOutputFormat->EqualsWithConversion("text/plain"))
|
||||
{ // only use these rules for plain text output
|
||||
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
||||
if (mFlags & nsIPlaintextEditor::eEditorPasswordMask)
|
||||
{
|
||||
*aOutString = mPasswordText;
|
||||
*aHandled = PR_TRUE;
|
||||
@ -1288,7 +1152,7 @@ nsTextEditRules::TruncateInsertionIfNeeded(nsISelection *aSelection,
|
||||
nsresult res = NS_OK;
|
||||
*aOutString = *aInString;
|
||||
|
||||
if ((-1 != aMaxLength) && (mFlags & nsIHTMLEditor::eEditorPlaintextMask))
|
||||
if ((-1 != aMaxLength) && (mFlags & nsIPlaintextEditor::eEditorPlaintextMask))
|
||||
{
|
||||
// Get the current text length.
|
||||
// Get the length of inString.
|
||||
@ -1388,69 +1252,3 @@ nsTextEditRules::DeleteEmptyTextNode(nsIDOMNode *aNode)
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection aDirection)
|
||||
{
|
||||
if (!aSelection) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// if the selection isn't collapsed, do nothing.
|
||||
PRBool bCollapsed;
|
||||
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!bCollapsed) return res;
|
||||
|
||||
// get the (collapsed) selection location
|
||||
nsCOMPtr<nsIDOMNode> selNode, temp;
|
||||
PRInt32 selOffset;
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
temp = selNode;
|
||||
|
||||
// are we in an editable node?
|
||||
while (!mEditor->IsEditable(selNode))
|
||||
{
|
||||
// scan up the tree until we find an editable place to be
|
||||
res = nsEditor::GetNodeLocation(temp, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!selNode) return NS_ERROR_FAILURE;
|
||||
temp = selNode;
|
||||
}
|
||||
|
||||
// are we in a text node?
|
||||
nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(selNode);
|
||||
if (textNode)
|
||||
return NS_OK; // we LIKE it when we are in a text node. that RULZ
|
||||
|
||||
// do we need to insert a special mozBR? We do if we are:
|
||||
// 1) after a block element AND
|
||||
// 2) at the end of the body OR before another block
|
||||
|
||||
nsCOMPtr<nsIDOMNode> priorNode, nextNode;
|
||||
res = mEditor->GetPriorHTMLSibling(selNode, selOffset, address_of(priorNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->GetNextHTMLSibling(selNode, selOffset, address_of(nextNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// is priorNode a block?
|
||||
if (priorNode && mEditor->IsBlockNode(priorNode))
|
||||
{
|
||||
if (!nextNode || mEditor->IsBlockNode(nextNode))
|
||||
{
|
||||
nsCOMPtr<nsISelection> sel(aSelection);
|
||||
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(sel));
|
||||
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
res = CreateMozBR(selNode, selOffset, address_of(brNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = nsEditor::GetNodeLocation(brNode, address_of(selNode), &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// selection stays *before* moz-br, sticking to it
|
||||
selPrivate->SetInterlinePosition(PR_TRUE);
|
||||
res = aSelection->Collapse(selNode,selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "nsHTMLEditor.h"
|
||||
#include "nsPlaintextEditor.h"
|
||||
#include "nsIDOMNode.h"
|
||||
|
||||
#include "nsEditRules.h"
|
||||
@ -50,7 +50,7 @@ public:
|
||||
virtual ~nsTextEditRules();
|
||||
|
||||
// nsIEditRules methods
|
||||
NS_IMETHOD Init(nsHTMLEditor *aEditor, PRUint32 aFlags);
|
||||
NS_IMETHOD Init(nsPlaintextEditor *aEditor, PRUint32 aFlags);
|
||||
NS_IMETHOD BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection);
|
||||
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection);
|
||||
NS_IMETHOD WillDoAction(nsISelection *aSelection, nsRulesInfo *aInfo, PRBool *aCancel, PRBool *aHandled);
|
||||
@ -163,17 +163,15 @@ protected:
|
||||
|
||||
PRBool DeleteEmptyTextNode(nsIDOMNode *aNode);
|
||||
|
||||
nsresult AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection aDirection);
|
||||
|
||||
// data members
|
||||
nsHTMLEditor *mEditor; // note that we do not refcount the editor
|
||||
nsString mPasswordText; // a buffer we use to store the real value of password editors
|
||||
nsCOMPtr<nsIDOMNode> mBogusNode; // magic node acts as placeholder in empty doc
|
||||
nsCOMPtr<nsIDOMNode> mBody; // cached root node
|
||||
PRUint32 mFlags;
|
||||
PRUint32 mActionNesting;
|
||||
PRBool mLockRulesSniffing;
|
||||
PRInt32 mTheAction; // the top level editor action
|
||||
nsPlaintextEditor *mEditor; // note that we do not refcount the editor
|
||||
nsString mPasswordText; // a buffer we use to store the real value of password editors
|
||||
nsCOMPtr<nsIDOMNode> mBogusNode; // magic node acts as placeholder in empty doc
|
||||
nsCOMPtr<nsIDOMNode> mBody; // cached root node
|
||||
PRUint32 mFlags;
|
||||
PRUint32 mActionNesting;
|
||||
PRBool mLockRulesSniffing;
|
||||
PRInt32 mTheAction; // the top level editor action
|
||||
// friends
|
||||
friend class nsAutoLockRulesSniffing;
|
||||
|
||||
|
Binary file not shown.
@ -5,6 +5,11 @@
|
||||
0xd3de3431, 0x8a75, 0x11d2, \
|
||||
{ 0x91, 0x8c, 0x0, 0x80, 0xc8, 0xe4, 0x4d, 0xb5 } }
|
||||
|
||||
#define NS_TEXTEDITOR_CID \
|
||||
{/* {e197cc01-cfe1-11d4-8eb0-87ae406dfd3f}*/ \
|
||||
0xe197cc01, 0xcfe1, 0x11d4, \
|
||||
{ 0x8e, 0xb0, 0x87, 0xae, 0x40, 0x6d, 0xfd, 0x3f } }
|
||||
|
||||
#define NS_HTMLEDITOR_CID \
|
||||
{/* {ed0244e0-c144-11d2-8f4c-006008159b0c}*/ \
|
||||
0xed0244e0, 0xc144, 0x11d2, \
|
||||
|
@ -140,6 +140,14 @@ public:
|
||||
*/
|
||||
NS_IMETHOD DeleteSelection(EDirection aAction)=0;
|
||||
|
||||
/**
|
||||
* DeleteSelectionAndCreateNode combines DeleteSelection and CreateNode
|
||||
* It deletes only if there is something selected (doesn't do DEL, BACKSPACE action)
|
||||
* @param aTag The type of object to create
|
||||
* @param aNewNode [OUT] The node created. Caller must release aNewNode.
|
||||
*/
|
||||
NS_IMETHOD DeleteSelectionAndCreateNode(const nsString& aTag, nsIDOMNode ** aNewNode)=0;
|
||||
|
||||
|
||||
/* ------------ Document info and file methods -------------- */
|
||||
|
||||
|
@ -45,45 +45,6 @@ class nsIHTMLEditor : public nsISupports
|
||||
public:
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IHTMLEDITOR_IID; return iid; }
|
||||
|
||||
|
||||
// the bits in an editor behavior mask.
|
||||
enum {
|
||||
eEditorPlaintextBit = 0, // only plain text entry is allowed via events
|
||||
eEditorSingleLineBit, // enter key and CR-LF handled specially
|
||||
eEditorPasswordBit, // text is not entered into content, only a representative character
|
||||
eEditorReadonlyBit, // editing events are disabled. Editor may still accept focus.
|
||||
eEditorDisabledBit, // all events are disabled (like scrolling). Editor will not accept focus.
|
||||
eEditorFilterInputBit, // text input is limited to certain character types, use mFilter
|
||||
eEditorMailBit, // use mail-compose editting rules
|
||||
eEditorDisableForcedUpdatesBit, // prevent immediate view refreshes
|
||||
eEditorDisableForcedReflowsBit, // prevent immediate reflows
|
||||
eEditorEnableWrapHackBit, // allow the editor to set font: monospace on the root node
|
||||
eEditorWidgetBit // bit for widgets
|
||||
|
||||
// max 32 bits
|
||||
};
|
||||
|
||||
enum {
|
||||
eEditorPlaintextMask = (1 << eEditorPlaintextBit),
|
||||
eEditorSingleLineMask = (1 << eEditorSingleLineBit),
|
||||
eEditorPasswordMask = (1 << eEditorPasswordBit),
|
||||
eEditorReadonlyMask = (1 << eEditorReadonlyBit),
|
||||
eEditorDisabledMask = (1 << eEditorDisabledBit),
|
||||
eEditorFilterInputMask = (1 << eEditorFilterInputBit),
|
||||
eEditorMailMask = (1 << eEditorMailBit),
|
||||
eEditorDisableForcedUpdatesMask = (1 << eEditorDisableForcedUpdatesBit),
|
||||
eEditorDisableForcedReflowsMask = (1 << eEditorDisableForcedReflowsBit),
|
||||
eEditorEnableWrapHackMask = (1 << eEditorEnableWrapHackBit),
|
||||
eEditorWidgetMask = (1 << eEditorWidgetBit)
|
||||
};
|
||||
|
||||
// below used by TypedText()
|
||||
enum {
|
||||
eTypedText, // user typed text
|
||||
eTypedBR, // user typed shift-enter to get a br
|
||||
eTypedBreak // user typed enter
|
||||
};
|
||||
|
||||
// used by GetAlignment()
|
||||
typedef enum {
|
||||
eLeft,
|
||||
@ -232,14 +193,6 @@ public:
|
||||
*/
|
||||
NS_IMETHOD InsertElementAtSelection(nsIDOMElement* aElement, PRBool aDeleteSelection)=0;
|
||||
|
||||
/**
|
||||
* DeleteSelectionAndCreateNode combines DeleteSelection and CreateNode
|
||||
* It deletes only if there is something selected (doesn't do DEL, BACKSPACE action)
|
||||
* @param aTag The type of object to create
|
||||
* @param aNewNode [OUT] The node created. Caller must release aNewNode.
|
||||
*/
|
||||
NS_IMETHOD DeleteSelectionAndCreateNode(const nsString& aTag, nsIDOMNode ** aNewNode)=0;
|
||||
|
||||
/* ------------ Selection manipulation -------------- */
|
||||
/* Should these be moved to nsISelection? */
|
||||
|
||||
|
@ -31,7 +31,6 @@
|
||||
#include "nsIFormControl.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIFrameSelection.h"
|
||||
#include "nsIHTMLEditor.h"
|
||||
#include "nsIPlaintextEditor.h"
|
||||
#include "nsEditorCID.h"
|
||||
#include "nsLayoutCID.h"
|
||||
@ -101,7 +100,7 @@
|
||||
#define GUESS_INPUT_SIZE 150 // 10 pixels wide
|
||||
|
||||
|
||||
static NS_DEFINE_CID(kHTMLEditorCID, NS_HTMLEDITOR_CID);
|
||||
static NS_DEFINE_CID(kTextEditorCID, NS_TEXTEDITOR_CID);
|
||||
static NS_DEFINE_CID(kFrameSelectionCID, NS_FRAMESELECTION_CID);
|
||||
|
||||
|
||||
@ -1612,8 +1611,8 @@ nsGfxTextControlFrame2::SetInitialValue()
|
||||
// immediate reflows during any editor calls.
|
||||
|
||||
rv = mEditor->SetFlags(editorFlags |
|
||||
nsIHTMLEditor::eEditorDisableForcedUpdatesMask |
|
||||
nsIHTMLEditor::eEditorDisableForcedReflowsMask);
|
||||
nsIPlaintextEditor::eEditorDisableForcedUpdatesMask |
|
||||
nsIPlaintextEditor::eEditorDisableForcedReflowsMask);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
@ -1751,9 +1750,10 @@ nsGfxTextControlFrame2::CreateAnonymousContent(nsIPresContext* aPresContext,
|
||||
|
||||
// Create an editor
|
||||
|
||||
rv = nsComponentManager::CreateInstance(kHTMLEditorCID,
|
||||
nsnull,
|
||||
NS_GET_IID(nsIEditor), getter_AddRefs(mEditor));
|
||||
rv = nsComponentManager::CreateInstance(kTextEditorCID,
|
||||
nsnull,
|
||||
NS_GET_IID(nsIEditor),
|
||||
getter_AddRefs(mEditor));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
if (!mEditor)
|
||||
@ -1784,14 +1784,14 @@ nsGfxTextControlFrame2::CreateAnonymousContent(nsIPresContext* aPresContext,
|
||||
|
||||
PRUint32 editorFlags = 0;
|
||||
if (IsPlainTextControl())
|
||||
editorFlags |= nsIHTMLEditor::eEditorPlaintextMask;
|
||||
editorFlags |= nsIPlaintextEditor::eEditorPlaintextMask;
|
||||
if (IsSingleLineTextControl())
|
||||
editorFlags |= nsIHTMLEditor::eEditorSingleLineMask;
|
||||
editorFlags |= nsIPlaintextEditor::eEditorSingleLineMask;
|
||||
if (IsPasswordTextControl())
|
||||
editorFlags |= nsIHTMLEditor::eEditorPasswordMask;
|
||||
editorFlags |= nsIPlaintextEditor::eEditorPasswordMask;
|
||||
|
||||
//all gfxtextcontrolframe2's are widgets
|
||||
editorFlags |= nsIHTMLEditor::eEditorWidgetMask;
|
||||
editorFlags |= nsIPlaintextEditor::eEditorWidgetMask;
|
||||
|
||||
// Now initialize the editor.
|
||||
//
|
||||
@ -1949,7 +1949,7 @@ nsGfxTextControlFrame2::CreateAnonymousContent(nsIPresContext* aPresContext,
|
||||
return rv;
|
||||
|
||||
if (NS_CONTENT_ATTR_NOT_THERE != rv)
|
||||
editorFlags |= nsIHTMLEditor::eEditorReadonlyMask;
|
||||
editorFlags |= nsIPlaintextEditor::eEditorReadonlyMask;
|
||||
|
||||
// Check if the disabled attribute is set.
|
||||
|
||||
@ -1959,18 +1959,18 @@ nsGfxTextControlFrame2::CreateAnonymousContent(nsIPresContext* aPresContext,
|
||||
return rv;
|
||||
|
||||
if (NS_CONTENT_ATTR_NOT_THERE != rv)
|
||||
editorFlags |= nsIHTMLEditor::eEditorDisabledMask;
|
||||
editorFlags |= nsIPlaintextEditor::eEditorDisabledMask;
|
||||
|
||||
// Disable the caret and selection if neccessary.
|
||||
|
||||
if (editorFlags & nsIHTMLEditor::eEditorReadonlyMask ||
|
||||
editorFlags & nsIHTMLEditor::eEditorDisabledMask)
|
||||
if (editorFlags & nsIPlaintextEditor::eEditorReadonlyMask ||
|
||||
editorFlags & nsIPlaintextEditor::eEditorDisabledMask)
|
||||
{
|
||||
if (mSelCon)
|
||||
{
|
||||
mSelCon->SetCaretEnabled(PR_FALSE);
|
||||
|
||||
if (editorFlags & nsIHTMLEditor::eEditorDisabledMask)
|
||||
if (editorFlags & nsIPlaintextEditor::eEditorDisabledMask)
|
||||
mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_OFF);
|
||||
}
|
||||
|
||||
@ -2689,14 +2689,14 @@ nsGfxTextControlFrame2::AttributeChanged(nsIPresContext* aPresContext,
|
||||
mEditor->GetFlags(&flags);
|
||||
if (NS_CONTENT_ATTR_NOT_THERE != rv)
|
||||
{ // set readonly
|
||||
flags |= nsIHTMLEditor::eEditorReadonlyMask;
|
||||
flags |= nsIPlaintextEditor::eEditorReadonlyMask;
|
||||
if (mSelCon)
|
||||
mSelCon->SetCaretEnabled(PR_FALSE);
|
||||
}
|
||||
else
|
||||
{ // unset readonly
|
||||
flags &= ~(nsIHTMLEditor::eEditorReadonlyMask);
|
||||
if (mSelCon && !(flags & nsIHTMLEditor::eEditorDisabledMask))
|
||||
flags &= ~(nsIPlaintextEditor::eEditorReadonlyMask);
|
||||
if (mSelCon && !(flags & nsIPlaintextEditor::eEditorDisabledMask))
|
||||
mSelCon->SetCaretEnabled(PR_TRUE);
|
||||
}
|
||||
mEditor->SetFlags(flags);
|
||||
@ -2713,7 +2713,7 @@ nsGfxTextControlFrame2::AttributeChanged(nsIPresContext* aPresContext,
|
||||
mEditor->GetFlags(&flags);
|
||||
if (NS_CONTENT_ATTR_NOT_THERE != rv)
|
||||
{ // set disabled
|
||||
flags |= nsIHTMLEditor::eEditorDisabledMask;
|
||||
flags |= nsIPlaintextEditor::eEditorDisabledMask;
|
||||
if (mSelCon)
|
||||
{
|
||||
mSelCon->SetCaretEnabled(PR_FALSE);
|
||||
@ -2722,10 +2722,10 @@ nsGfxTextControlFrame2::AttributeChanged(nsIPresContext* aPresContext,
|
||||
}
|
||||
else
|
||||
{ // unset disabled
|
||||
flags &= ~(nsIHTMLEditor::eEditorDisabledMask);
|
||||
flags &= ~(nsIPlaintextEditor::eEditorDisabledMask);
|
||||
if (mSelCon)
|
||||
{
|
||||
if (! (flags & nsIHTMLEditor::eEditorReadonlyMask))
|
||||
if (! (flags & nsIPlaintextEditor::eEditorReadonlyMask))
|
||||
mSelCon->SetCaretEnabled(PR_TRUE);
|
||||
mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
|
||||
}
|
||||
@ -3019,15 +3019,15 @@ nsGfxTextControlFrame2::SetTextControlFrameState(const nsAReadableString& aValue
|
||||
if (NS_FAILED(rv)) return;
|
||||
if (!domDoc) return;
|
||||
mSelCon->SelectAll();
|
||||
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
|
||||
nsCOMPtr<nsIPlaintextEditor> htmlEditor = do_QueryInterface(mEditor);
|
||||
if (!htmlEditor) return;
|
||||
|
||||
// get the flags, remove readonly and disabled, set the value, restore flags
|
||||
PRUint32 flags, savedFlags;
|
||||
mEditor->GetFlags(&savedFlags);
|
||||
flags = savedFlags;
|
||||
flags &= ~(nsIHTMLEditor::eEditorDisabledMask);
|
||||
flags &= ~(nsIHTMLEditor::eEditorReadonlyMask);
|
||||
flags &= ~(nsIPlaintextEditor::eEditorDisabledMask);
|
||||
flags &= ~(nsIPlaintextEditor::eEditorReadonlyMask);
|
||||
mEditor->SetFlags(flags);
|
||||
if (currentValue.Length() < 1)
|
||||
mEditor->DeleteSelection(nsIEditor::eNone);
|
||||
|
Loading…
Reference in New Issue
Block a user