зеркало из https://github.com/mozilla/gecko-dev.git
making editor hip to inline style changes on collapsed selections. plus lots of removal of unused code.
This commit is contained in:
Родитель
3ff6fe1c16
Коммит
af4644e7c8
|
@ -24,6 +24,9 @@
|
|||
|
||||
#include "TypeInState.h"
|
||||
|
||||
/********************************************************************
|
||||
* XPCOM cruft
|
||||
*******************************************************************/
|
||||
|
||||
NS_IMPL_ADDREF(TypeInState)
|
||||
NS_IMPL_RELEASE(TypeInState)
|
||||
|
@ -47,12 +50,282 @@ TypeInState::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* public methods
|
||||
*******************************************************************/
|
||||
|
||||
TypeInState::TypeInState() :
|
||||
mSetArray()
|
||||
,mClearedArray()
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
Reset();
|
||||
}
|
||||
|
||||
TypeInState::~TypeInState()
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
NS_IMETHODIMP TypeInState::NotifySelectionChanged()
|
||||
{
|
||||
Reset();
|
||||
return NS_OK;
|
||||
};
|
||||
}
|
||||
|
||||
void TypeInState::Reset()
|
||||
{
|
||||
PRInt32 count;
|
||||
PropItem *propItemPtr;
|
||||
|
||||
while ((count = mClearedArray.Count()))
|
||||
{
|
||||
// go backwards to keep nsVoidArray from memmoving everything each time
|
||||
count--; // nsVoidArray is zero based
|
||||
propItemPtr = (PropItem*)mClearedArray.ElementAt(count);
|
||||
mClearedArray.RemoveElementAt(count);
|
||||
if (propItemPtr) delete propItemPtr;
|
||||
}
|
||||
while ((count = mSetArray.Count()))
|
||||
{
|
||||
// go backwards to keep nsVoidArray from memmoving everything each time
|
||||
count--; // nsVoidArray is zero based
|
||||
propItemPtr = (PropItem*)mSetArray.ElementAt(count);
|
||||
mSetArray.RemoveElementAt(count);
|
||||
if (propItemPtr) delete propItemPtr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsresult TypeInState::SetProp(nsIAtom *aProp)
|
||||
{
|
||||
return SetProp(aProp,nsAutoString(),nsAutoString());
|
||||
}
|
||||
|
||||
nsresult TypeInState::SetProp(nsIAtom *aProp, const nsString &aAttr)
|
||||
{
|
||||
return SetProp(aProp,aAttr,nsAutoString());
|
||||
}
|
||||
|
||||
nsresult TypeInState::SetProp(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue)
|
||||
{
|
||||
// if it's already set we are done
|
||||
if (IsPropSet(aProp,aAttr,aValue)) return NS_OK;
|
||||
|
||||
// make a new propitem
|
||||
PropItem *item = new PropItem(aProp,aAttr,aValue);
|
||||
if (!item) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// remove it from the list of cleared properties, if we have a match
|
||||
RemovePropFromClearedList(aProp,aAttr,aValue);
|
||||
|
||||
// add it to the list of set properties
|
||||
mSetArray.AppendElement((void*)item);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult TypeInState::ClearProp(nsIAtom *aProp)
|
||||
{
|
||||
return ClearProp(aProp,nsAutoString(),nsAutoString());
|
||||
}
|
||||
|
||||
nsresult TypeInState::ClearProp(nsIAtom *aProp, const nsString &aAttr)
|
||||
{
|
||||
return ClearProp(aProp,aAttr,nsAutoString());
|
||||
}
|
||||
|
||||
nsresult TypeInState::ClearProp(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue)
|
||||
{
|
||||
// if it's already cleared we are done
|
||||
if (IsPropCleared(aProp,aAttr,aValue)) return NS_OK;
|
||||
|
||||
// make a new propitem
|
||||
PropItem *item = new PropItem(aProp,aAttr,aValue);
|
||||
if (!item) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// remove it from the list of set properties, if we have a match
|
||||
RemovePropFromSetList(aProp,aAttr,aValue);
|
||||
|
||||
// add it to the list of cleared properties
|
||||
mClearedArray.AppendElement((void*)item);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
nsresult TypeInState::ProcessClearProperty(PropItem **outPropItem)
|
||||
{
|
||||
if (!outPropItem) return NS_ERROR_NULL_POINTER;
|
||||
*outPropItem = nsnull;
|
||||
PRInt32 count = mClearedArray.Count();
|
||||
if (count) // go backwards to keep nsVoidArray from memmoving everything each time
|
||||
{
|
||||
count--; // nsVoidArray is zero based
|
||||
*outPropItem = (PropItem*)mClearedArray[count];
|
||||
mClearedArray.RemoveElementAt(count);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult TypeInState::ProcessSetProperty(PropItem **outPropItem)
|
||||
{
|
||||
if (!outPropItem) return NS_ERROR_NULL_POINTER;
|
||||
*outPropItem = nsnull;
|
||||
PRInt32 count = mSetArray.Count();
|
||||
if (count) // go backwards to keep nsVoidArray from memmoving everything each time
|
||||
{
|
||||
count--; // nsVoidArray is zero based
|
||||
*outPropItem = (PropItem*)mSetArray[count];
|
||||
mSetArray.RemoveElementAt(count);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult TypeInState::GetTypingState(PRBool &isSet, PRBool &theSetting, nsIAtom *aProp)
|
||||
{
|
||||
return GetTypingState(isSet, theSetting, aProp, nsAutoString(), nsAutoString());
|
||||
}
|
||||
|
||||
nsresult TypeInState::GetTypingState(PRBool &isSet,
|
||||
PRBool &theSetting,
|
||||
nsIAtom *aProp,
|
||||
const nsString &aAttr)
|
||||
{
|
||||
return GetTypingState(isSet, theSetting, aProp, aAttr, nsAutoString());
|
||||
}
|
||||
|
||||
|
||||
nsresult TypeInState::GetTypingState(PRBool &isSet,
|
||||
PRBool &theSetting,
|
||||
nsIAtom *aProp,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue)
|
||||
{
|
||||
if (IsPropSet(aProp, aAttr, aValue))
|
||||
{
|
||||
isSet = PR_TRUE;
|
||||
theSetting = PR_TRUE;
|
||||
}
|
||||
else if (IsPropCleared(aProp, aAttr, aValue))
|
||||
{
|
||||
isSet = PR_TRUE;
|
||||
theSetting = PR_FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
isSet = PR_FALSE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* protected methods
|
||||
*******************************************************************/
|
||||
|
||||
nsresult TypeInState::RemovePropFromSetList(nsIAtom *aProp,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue)
|
||||
{
|
||||
PRInt32 index;
|
||||
if (IsPropSet(aProp, aAttr, aValue, index))
|
||||
{
|
||||
PropItem *item = (PropItem*)mSetArray.ElementAt(index);
|
||||
mSetArray.RemoveElementAt(index);
|
||||
if (item) delete item;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult TypeInState::RemovePropFromClearedList(nsIAtom *aProp,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue)
|
||||
{
|
||||
PRInt32 index;
|
||||
if (IsPropCleared(aProp, aAttr, aValue, index))
|
||||
{
|
||||
PropItem *item = (PropItem*)mClearedArray.ElementAt(index);
|
||||
mClearedArray.RemoveElementAt(index);
|
||||
if (item) delete item;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
PRBool TypeInState::IsPropSet(nsIAtom *aProp,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue)
|
||||
{
|
||||
PRInt32 i;
|
||||
return IsPropSet(aProp, aAttr, aValue, i);
|
||||
}
|
||||
|
||||
|
||||
PRBool TypeInState::IsPropSet(nsIAtom *aProp,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue,
|
||||
PRInt32 &outIndex)
|
||||
{
|
||||
PRInt32 i, count = mSetArray.Count();
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
PropItem *item = (PropItem*)mSetArray[i];
|
||||
if ( (item->tag == aProp) &&
|
||||
(item->attr == aAttr) )
|
||||
{
|
||||
outIndex = i;
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
PRBool TypeInState::IsPropCleared(nsIAtom *aProp,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue)
|
||||
{
|
||||
PRInt32 i;
|
||||
return IsPropCleared(aProp, aAttr, aValue, i);
|
||||
}
|
||||
|
||||
|
||||
PRBool TypeInState::IsPropCleared(nsIAtom *aProp,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue,
|
||||
PRInt32 &outIndex)
|
||||
{
|
||||
PRInt32 i, count = mSetArray.Count();
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
PropItem *item = (PropItem*)mSetArray[i];
|
||||
if ( (item->tag == aProp) &&
|
||||
(item->attr == aAttr) )
|
||||
{
|
||||
outIndex = i;
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* PropItem: helper struct for TypeInState
|
||||
*******************************************************************/
|
||||
|
||||
PropItem::PropItem(nsIAtom *aTag, const nsString &aAttr, const nsString &aValue) :
|
||||
tag(aTag)
|
||||
,attr(aAttr)
|
||||
,value(aValue)
|
||||
{
|
||||
}
|
||||
|
||||
PropItem::~PropItem()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -26,6 +26,17 @@
|
|||
#include "nsIDOMSelectionListener.h"
|
||||
#include "nsIEditProperty.h"
|
||||
#include "nsString.h"
|
||||
#include "nsVoidArray.h"
|
||||
|
||||
struct PropItem
|
||||
{
|
||||
nsIAtom *tag;
|
||||
nsString attr;
|
||||
nsString value;
|
||||
|
||||
PropItem(nsIAtom *aTag, const nsString &aAttr, const nsString &aValue);
|
||||
~PropItem();
|
||||
};
|
||||
|
||||
class TypeInState : public nsIDOMSelectionListener
|
||||
{
|
||||
|
@ -39,260 +50,35 @@ public:
|
|||
|
||||
NS_IMETHOD NotifySelectionChanged();
|
||||
|
||||
void GetEnumForName(nsIAtom *aPropName, PRUint32 &aEnum);
|
||||
void GetPropertyIsString(PRUint32 aProp, PRUint32 &aIsString);
|
||||
|
||||
void SetProp(PRUint32 aProp, PRBool aSet);
|
||||
void GetProp(PRUint32 aProp, PRBool& aSet);
|
||||
|
||||
void SetPropValue(PRUint32 aProp, const nsString &aValue);
|
||||
void GetPropValue(PRUint32 aProp, nsString &aValue);
|
||||
|
||||
PRBool IsSet(PRUint32 aStyle);
|
||||
PRBool IsAnySet();
|
||||
void UnSet(PRUint32 aStyle);
|
||||
|
||||
void SetBold(PRBool aIsSet);
|
||||
PRBool GetBold();
|
||||
|
||||
void SetItalic(PRBool aIsSet);
|
||||
PRBool GetItalic();
|
||||
|
||||
void SetUnderline(PRBool aIsSet);
|
||||
PRBool GetUnderline();
|
||||
nsresult SetProp(nsIAtom *aProp);
|
||||
nsresult SetProp(nsIAtom *aProp, const nsString &aAttr);
|
||||
nsresult SetProp(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue);
|
||||
nsresult ClearProp(nsIAtom *aProp);
|
||||
nsresult ClearProp(nsIAtom *aProp, const nsString &aAttr);
|
||||
nsresult ClearProp(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue);
|
||||
|
||||
void SetFontFace(const nsString &aFace);
|
||||
void GetFontFace(nsString &aFace);
|
||||
|
||||
void SetFontColor(const nsString &aColor);
|
||||
void GetFontColor(nsString &aColor);
|
||||
|
||||
void SetFontSize(const nsString &aSize);
|
||||
void GetFontSize(nsString &aSize);
|
||||
nsresult ProcessClearProperty(PropItem **outPropItem);
|
||||
nsresult ProcessSetProperty(PropItem **outPropItem);
|
||||
|
||||
nsresult GetTypingState(PRBool &isSet, PRBool &theSetting, nsIAtom *aProp);
|
||||
nsresult GetTypingState(PRBool &isSet, PRBool &theSetting, nsIAtom *aProp,
|
||||
const nsString &aAttr);
|
||||
nsresult GetTypingState(PRBool &isSet, PRBool &theSetting, nsIAtom *aProp,
|
||||
const nsString &aAttr, const nsString &aValue);
|
||||
|
||||
protected:
|
||||
PRBool mBold;
|
||||
PRBool mItalic;
|
||||
PRBool mUnderline;
|
||||
nsString mFontFace;
|
||||
nsString mFontColor;
|
||||
nsString mFontSize;
|
||||
PRUint32 mIsSet;
|
||||
|
||||
nsresult RemovePropFromSetList(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue);
|
||||
nsresult RemovePropFromClearedList(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue);
|
||||
PRBool IsPropSet(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue);
|
||||
PRBool IsPropSet(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue, PRInt32 &outIndex);
|
||||
PRBool IsPropCleared(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue);
|
||||
PRBool IsPropCleared(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue, PRInt32 &outIndex);
|
||||
|
||||
nsVoidArray mSetArray;
|
||||
nsVoidArray mClearedArray;
|
||||
};
|
||||
|
||||
#define NS_TYPEINSTATE_UNKNOWN 0x00000000
|
||||
#define NS_TYPEINSTATE_BOLD 0x00000001
|
||||
#define NS_TYPEINSTATE_ITALIC 0x00000002
|
||||
#define NS_TYPEINSTATE_UNDERLINE 0x00000004
|
||||
#define NS_TYPEINSTATE_FONTFACE 0x00000008
|
||||
#define NS_TYPEINSTATE_FONTCOLOR 0x00000010
|
||||
#define NS_TYPEINSTATE_FONTSIZE 0x00000020
|
||||
|
||||
/* ----- inline method definitions ----- */
|
||||
inline
|
||||
void TypeInState::Reset()
|
||||
{
|
||||
mBold = PR_FALSE;
|
||||
mItalic = PR_FALSE;
|
||||
mUnderline = PR_FALSE;
|
||||
mIsSet = 0;
|
||||
};
|
||||
|
||||
inline
|
||||
TypeInState::TypeInState()
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
Reset();
|
||||
};
|
||||
|
||||
inline
|
||||
void TypeInState::GetEnumForName(nsIAtom *aPropName, PRUint32 &aEnum)
|
||||
{
|
||||
aEnum = NS_TYPEINSTATE_UNKNOWN;
|
||||
if (nsIEditProperty::b==aPropName) { aEnum = NS_TYPEINSTATE_BOLD; }
|
||||
else if (nsIEditProperty::i==aPropName) { aEnum = NS_TYPEINSTATE_ITALIC; }
|
||||
else if (nsIEditProperty::u==aPropName) { aEnum = NS_TYPEINSTATE_UNDERLINE; }
|
||||
else if (nsIEditProperty::face==aPropName) { aEnum = NS_TYPEINSTATE_FONTFACE; }
|
||||
else if (nsIEditProperty::color==aPropName) { aEnum = NS_TYPEINSTATE_FONTCOLOR; }
|
||||
else if (nsIEditProperty::size==aPropName) { aEnum = NS_TYPEINSTATE_FONTSIZE; }
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
void TypeInState::GetPropertyIsString(PRUint32 aProp, PRUint32 &aIsString)
|
||||
{
|
||||
switch (aProp)
|
||||
{
|
||||
case NS_TYPEINSTATE_BOLD:
|
||||
case NS_TYPEINSTATE_ITALIC:
|
||||
case NS_TYPEINSTATE_UNDERLINE:
|
||||
aIsString = PR_FALSE;
|
||||
break;
|
||||
|
||||
case NS_TYPEINSTATE_FONTFACE:
|
||||
case NS_TYPEINSTATE_FONTCOLOR:
|
||||
case NS_TYPEINSTATE_FONTSIZE:
|
||||
aIsString = PR_TRUE;
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("Unknown property");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
PRBool TypeInState::IsSet(PRUint32 aStyle)
|
||||
{
|
||||
if ((PRBool)(mIsSet & aStyle))
|
||||
return PR_TRUE;
|
||||
else
|
||||
return PR_FALSE;
|
||||
};
|
||||
|
||||
inline
|
||||
void TypeInState::UnSet(PRUint32 aStyle)
|
||||
{
|
||||
mIsSet &= ~aStyle;
|
||||
};
|
||||
|
||||
inline
|
||||
PRBool TypeInState::IsAnySet()
|
||||
{
|
||||
return (PRBool)(0!=mIsSet);
|
||||
}
|
||||
|
||||
inline
|
||||
void TypeInState::SetBold(PRBool aIsSet)
|
||||
{
|
||||
mBold = aIsSet;
|
||||
mIsSet |= NS_TYPEINSTATE_BOLD;
|
||||
};
|
||||
|
||||
inline
|
||||
PRBool TypeInState::GetBold()
|
||||
{ return mBold;};
|
||||
|
||||
inline
|
||||
void TypeInState::SetItalic(PRBool aIsSet)
|
||||
{
|
||||
mItalic = aIsSet;
|
||||
mIsSet |= NS_TYPEINSTATE_ITALIC;
|
||||
};
|
||||
|
||||
inline
|
||||
PRBool TypeInState::GetItalic()
|
||||
{ return mItalic; };
|
||||
|
||||
inline
|
||||
void TypeInState::SetUnderline(PRBool aIsSet)
|
||||
{
|
||||
mUnderline = aIsSet;
|
||||
mIsSet |= NS_TYPEINSTATE_UNDERLINE;
|
||||
};
|
||||
|
||||
inline
|
||||
PRBool TypeInState::GetUnderline()
|
||||
{ return mUnderline; };
|
||||
|
||||
inline
|
||||
void TypeInState::SetFontFace(const nsString &aFace)
|
||||
{
|
||||
mFontFace = aFace;
|
||||
mIsSet |= NS_TYPEINSTATE_FONTFACE;
|
||||
};
|
||||
|
||||
inline
|
||||
void TypeInState::GetFontFace(nsString &aFace)
|
||||
{ aFace = mFontFace; };
|
||||
|
||||
inline
|
||||
void TypeInState::SetFontColor(const nsString &aColor)
|
||||
{
|
||||
mFontColor = aColor;
|
||||
mIsSet |= NS_TYPEINSTATE_FONTCOLOR;
|
||||
};
|
||||
|
||||
inline
|
||||
void TypeInState::GetFontColor(nsString &aColor)
|
||||
{ aColor = mFontColor; };
|
||||
|
||||
inline
|
||||
void TypeInState::SetFontSize(const nsString &aSize)
|
||||
{
|
||||
mFontSize = aSize;
|
||||
mIsSet |= NS_TYPEINSTATE_FONTSIZE;
|
||||
};
|
||||
|
||||
inline
|
||||
void TypeInState::GetFontSize(nsString &aSize)
|
||||
{ aSize = mFontSize; };
|
||||
|
||||
inline void TypeInState::SetProp(PRUint32 aProp, PRBool aSet)
|
||||
{
|
||||
switch (aProp)
|
||||
{
|
||||
case NS_TYPEINSTATE_BOLD:
|
||||
SetBold(aSet);
|
||||
break;
|
||||
case NS_TYPEINSTATE_ITALIC:
|
||||
SetItalic(aSet);
|
||||
break;
|
||||
case NS_TYPEINSTATE_UNDERLINE:
|
||||
SetUnderline(aSet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline void TypeInState::SetPropValue(PRUint32 aProp, const nsString &aValue)
|
||||
{
|
||||
switch (aProp)
|
||||
{
|
||||
case NS_TYPEINSTATE_FONTFACE:
|
||||
SetFontFace(aValue);
|
||||
break;
|
||||
case NS_TYPEINSTATE_FONTCOLOR:
|
||||
SetFontColor(aValue);
|
||||
break;
|
||||
case NS_TYPEINSTATE_FONTSIZE:
|
||||
SetFontSize(aValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
void TypeInState::GetProp(PRUint32 aProp, PRBool& aSet)
|
||||
{
|
||||
switch (aProp)
|
||||
{
|
||||
case NS_TYPEINSTATE_BOLD:
|
||||
aSet = GetBold();
|
||||
break;
|
||||
case NS_TYPEINSTATE_ITALIC:
|
||||
aSet = GetItalic();
|
||||
break;
|
||||
case NS_TYPEINSTATE_UNDERLINE:
|
||||
aSet = GetUnderline();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
void TypeInState::GetPropValue(PRUint32 aProp, nsString &aValue)
|
||||
{
|
||||
switch (aProp)
|
||||
{
|
||||
case NS_TYPEINSTATE_FONTFACE:
|
||||
GetFontFace(aValue);
|
||||
break;
|
||||
case NS_TYPEINSTATE_FONTCOLOR:
|
||||
GetFontColor(aValue);
|
||||
break;
|
||||
case NS_TYPEINSTATE_FONTSIZE:
|
||||
GetFontSize(aValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // TypeInState_h__
|
||||
|
|
|
@ -1472,23 +1472,6 @@ nsEditor::SaveFile(nsFileSpec *aFileSpec, PRBool aReplaceExisting, PRBool aSaveC
|
|||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::SetProperties(nsVoidArray * aPropList)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::GetProperties(nsVoidArray *aPropList)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
*/
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::SetAttribute(nsIDOMElement *aElement, const nsString& aAttribute, const nsString& aValue)
|
||||
{
|
||||
|
@ -1538,47 +1521,6 @@ nsEditor::RemoveAttribute(nsIDOMElement *aElement, const nsString& aAttribute)
|
|||
}
|
||||
|
||||
|
||||
//
|
||||
// Insert a noneditable text node, e.g. formatting whitespace
|
||||
//
|
||||
nsresult
|
||||
nsEditor::InsertNoneditableTextNode(nsIDOMNode* parent, PRInt32 offset,
|
||||
nsString& aStr)
|
||||
{
|
||||
nsAutoString textNodeTag;
|
||||
nsresult res = GetTextNodeTag(textNodeTag);
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
|
||||
// Can't call CreateNode, because that will call us recursively.
|
||||
// So duplicate what it does:
|
||||
CreateElementTxn *txn;
|
||||
res = CreateTxnForCreateElement(textNodeTag, parent, offset, &txn);
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
|
||||
res = Do(txn);
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
|
||||
// Now get the pointer to the node we just created ...
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
res = txn->GetNewNode(getter_AddRefs(newNode));
|
||||
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
nsCOMPtr<nsIDOMCharacterData> newTextNode;
|
||||
newTextNode = do_QueryInterface(newNode);
|
||||
if (!newTextNode)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// ... and set its text.
|
||||
return newTextNode->SetData(aStr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::MarkNodeDirty(nsIDOMNode* aNode)
|
||||
{
|
||||
|
@ -2563,27 +2505,48 @@ NS_IMETHODIMP nsEditor::JoeInsertTextImpl(const nsString& aStringToInsert,
|
|||
nsCOMPtr<nsIDOMText> nodeAsText = do_QueryInterface(*aInOutNode);
|
||||
PRInt32 offset = *aInOutOffset;
|
||||
nsresult res;
|
||||
if (nodeAsText)
|
||||
if (mInIMEMode)
|
||||
{
|
||||
// we are inserting text into an existing text node.
|
||||
if (!nodeAsText)
|
||||
{
|
||||
// create a text node
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
res = aDoc->CreateTextNode("", getter_AddRefs(nodeAsText));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!nodeAsText) return NS_ERROR_NULL_POINTER;
|
||||
newNode = do_QueryInterface(nodeAsText);
|
||||
// then we insert it into the dom tree
|
||||
res = InsertNode(newNode, *aInOutNode, offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
offset = 0;
|
||||
}
|
||||
res = JoeInsertTextIntoTextNodeImpl(aStringToInsert, nodeAsText, offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
*aInOutOffset += aStringToInsert.Length();
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
// we are inserting text into a non-text node
|
||||
// first we have to create a textnode (this also populates it with the text)
|
||||
res = aDoc->CreateTextNode(aStringToInsert, getter_AddRefs(nodeAsText));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!nodeAsText) return NS_ERROR_NULL_POINTER;
|
||||
newNode = do_QueryInterface(nodeAsText);
|
||||
// then we insert it into the dom tree
|
||||
res = InsertNode(newNode, *aInOutNode, offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
*aInOutNode = newNode;
|
||||
*aInOutOffset = aStringToInsert.Length();
|
||||
if (nodeAsText)
|
||||
{
|
||||
// we are inserting text into an existing text node.
|
||||
res = JoeInsertTextIntoTextNodeImpl(aStringToInsert, nodeAsText, offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
*aInOutOffset += aStringToInsert.Length();
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
// we are inserting text into a non-text node
|
||||
// first we have to create a textnode (this also populates it with the text)
|
||||
res = aDoc->CreateTextNode(aStringToInsert, getter_AddRefs(nodeAsText));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!nodeAsText) return NS_ERROR_NULL_POINTER;
|
||||
newNode = do_QueryInterface(nodeAsText);
|
||||
// then we insert it into the dom tree
|
||||
res = InsertNode(newNode, *aInOutNode, offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
*aInOutNode = newNode;
|
||||
*aInOutOffset = aStringToInsert.Length();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -2594,7 +2557,20 @@ NS_IMETHODIMP nsEditor::JoeInsertTextIntoTextNodeImpl(const nsString& aStringToI
|
|||
PRInt32 aOffset)
|
||||
{
|
||||
EditTxn *txn;
|
||||
nsresult result = CreateTxnForInsertText(aStringToInsert, aTextNode, aOffset, (InsertTextTxn**)&txn);
|
||||
nsresult result;
|
||||
if (mInIMEMode)
|
||||
{
|
||||
if (!mIMETextNode)
|
||||
{
|
||||
mIMETextNode = aTextNode;
|
||||
mIMETextOffset = aOffset;
|
||||
}
|
||||
result = CreateTxnForIMEText(aStringToInsert, (IMETextTxn**)&txn);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = CreateTxnForInsertText(aStringToInsert, aTextNode, aOffset, (InsertTextTxn**)&txn);
|
||||
}
|
||||
if (NS_FAILED(result)) return result;
|
||||
|
||||
// let listeners know whats up
|
||||
|
@ -2632,148 +2608,6 @@ NS_IMETHODIMP nsEditor::JoeInsertTextIntoTextNodeImpl(const nsString& aStringToI
|
|||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsEditor::InsertTextImpl(const nsString& aStringToInsert)
|
||||
{
|
||||
// First delete the selection if needed
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
nsresult result = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(result)) return result;
|
||||
if (!selection) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
PRBool bIsCollapsed;
|
||||
selection->GetIsCollapsed(&bIsCollapsed);
|
||||
if (!bIsCollapsed)
|
||||
{
|
||||
result = DeleteSelectionImpl(nsIEditor::eNone);
|
||||
if (NS_FAILED(result)) return result;
|
||||
}
|
||||
|
||||
PRInt32 action = kOpInsertText;
|
||||
if (mInIMEMode) action = kOpInsertIMEText;
|
||||
nsAutoRules beginRulesSniffing(this, action, nsIEditor::eNext);
|
||||
|
||||
nsCOMPtr<nsIDOMCharacterData> nodeAsText;
|
||||
PRInt32 offset;
|
||||
result = PrepareToInsertText(&nodeAsText, &offset);
|
||||
|
||||
if (NS_SUCCEEDED(result))
|
||||
{
|
||||
EditTxn *txn;
|
||||
if (mInIMEMode)
|
||||
{
|
||||
if (!mIMETextNode)
|
||||
{
|
||||
mIMETextNode = nodeAsText;
|
||||
mIMETextOffset = offset;
|
||||
}
|
||||
result = CreateTxnForIMEText(aStringToInsert,(IMETextTxn**)&txn);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = CreateTxnForInsertText(aStringToInsert, nodeAsText, offset, (InsertTextTxn**)&txn);
|
||||
}
|
||||
if (NS_FAILED(result)) return result;
|
||||
if (!txn) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// let listeners know whats up
|
||||
PRInt32 i;
|
||||
nsIEditActionListener *listener;
|
||||
if (mActionListeners)
|
||||
{
|
||||
for (i = 0; i < mActionListeners->Count(); i++)
|
||||
{
|
||||
listener = (nsIEditActionListener *)mActionListeners->ElementAt(i);
|
||||
if (listener)
|
||||
listener->WillInsertText(nodeAsText, offset, aStringToInsert);
|
||||
}
|
||||
}
|
||||
|
||||
BeginUpdateViewBatch();
|
||||
result = Do(txn);
|
||||
// The transaction system (if any) has taken ownwership of txns.
|
||||
// aggTxn released at end of routine.
|
||||
NS_IF_RELEASE(txn);
|
||||
EndUpdateViewBatch();
|
||||
|
||||
// let listeners know what happened
|
||||
if (mActionListeners)
|
||||
{
|
||||
for (i = 0; i < mActionListeners->Count(); i++)
|
||||
{
|
||||
listener = (nsIEditActionListener *)mActionListeners->ElementAt(i);
|
||||
if (listener)
|
||||
listener->DidInsertText(nodeAsText, offset, aStringToInsert, result);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (NS_ERROR_EDITOR_NO_TEXTNODE==result)
|
||||
{
|
||||
// create the text node
|
||||
nsCOMPtr<nsIDOMNode> selectedNode;
|
||||
result = selection->GetAnchorNode(getter_AddRefs(selectedNode));
|
||||
if (NS_SUCCEEDED(result) && NS_SUCCEEDED(selection->GetAnchorOffset(&offset)) && selectedNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
nsAutoString textNodeTag;
|
||||
result = GetTextNodeTag(textNodeTag);
|
||||
if (NS_FAILED(result)) { return result; }
|
||||
result = CreateNode(textNodeTag, selectedNode, offset,
|
||||
getter_AddRefs(newNode));
|
||||
if (NS_SUCCEEDED(result) && newNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMCharacterData>newTextNode;
|
||||
newTextNode = do_QueryInterface(newNode);
|
||||
if (newTextNode)
|
||||
{
|
||||
selection->Collapse(newNode, 0);
|
||||
result = InsertTextImpl(aStringToInsert); // this really recurses, right?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsEditor::PrepareToInsertText(nsCOMPtr<nsIDOMCharacterData> *aOutTextNode, PRInt32 *aOutOffset)
|
||||
{
|
||||
if (!aOutTextNode || !aOutOffset) return NS_ERROR_NULL_POINTER;
|
||||
nsresult result = NS_OK;
|
||||
nsCOMPtr<nsIDOMCharacterData> nodeAsText;
|
||||
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
result = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(result)) return result;
|
||||
if (!selection) return NS_ERROR_NULL_POINTER;
|
||||
nsCOMPtr<nsIDOMNode> selNode;
|
||||
result = GetStartNodeAndOffset(selection, &selNode, aOutOffset);
|
||||
if (NS_FAILED(result)) return result;
|
||||
if (!selNode)
|
||||
{
|
||||
// should nsEditor really be concerned with the body node?
|
||||
// That's an html concept.
|
||||
nsCOMPtr<nsIDOMElement>bodyElement;
|
||||
result = GetBodyElement(getter_AddRefs(bodyElement));
|
||||
if (NS_FAILED(result)) return result;
|
||||
if (!bodyElement) return NS_ERROR_NULL_POINTER;
|
||||
nsCOMPtr<nsIDOMNode>bodyNode = do_QueryInterface(bodyElement);
|
||||
selection->Collapse(bodyNode,0);
|
||||
result = GetStartNodeAndOffset(selection, &selNode, aOutOffset);
|
||||
if (NS_FAILED(result)) return result;
|
||||
}
|
||||
|
||||
nodeAsText = do_QueryInterface(selNode);
|
||||
if (nodeAsText)
|
||||
{
|
||||
*aOutTextNode = nodeAsText;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = NS_ERROR_EDITOR_NO_TEXTNODE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsEditor::SelectEntireDocument(nsIDOMSelection *aSelection)
|
||||
{
|
||||
nsresult result;
|
||||
|
@ -3513,244 +3347,6 @@ nsEditor::IsNodeInline(nsIDOMNode *aNode, PRBool &aIsInline)
|
|||
return result;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEditor::GetBlockParent(nsIDOMNode *aNode, nsIDOMElement **aBlockParent)
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
if (!aBlockParent) {return NS_ERROR_NULL_POINTER;}
|
||||
*aBlockParent = nsnull;
|
||||
nsCOMPtr<nsIDOMNode>parent;
|
||||
nsCOMPtr<nsIDOMNode>temp;
|
||||
result = aNode->GetParentNode(getter_AddRefs(parent));
|
||||
while (NS_SUCCEEDED(result) && parent)
|
||||
{
|
||||
PRBool isInline;
|
||||
result = IsNodeInline(parent, isInline);
|
||||
if (PR_FALSE==isInline)
|
||||
{
|
||||
parent->QueryInterface(NS_GET_IID(nsIDOMElement), (void**)aBlockParent);
|
||||
break;
|
||||
}
|
||||
result = parent->GetParentNode(getter_AddRefs(temp));
|
||||
parent = do_QueryInterface(temp);
|
||||
}
|
||||
if (gNoisy) {
|
||||
printf("GetBlockParent for %p returning parent %p\n", aNode, *aBlockParent);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEditor::GetBlockSection(nsIDOMNode *aChild,
|
||||
nsIDOMNode **aLeftNode,
|
||||
nsIDOMNode **aRightNode)
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
if (!aChild || !aLeftNode || !aRightNode) {return NS_ERROR_NULL_POINTER;}
|
||||
*aLeftNode = aChild;
|
||||
*aRightNode = aChild;
|
||||
|
||||
nsCOMPtr<nsIDOMNode>sibling;
|
||||
result = aChild->GetPreviousSibling(getter_AddRefs(sibling));
|
||||
while ((NS_SUCCEEDED(result)) && sibling)
|
||||
{
|
||||
PRBool isInline;
|
||||
IsNodeInline(sibling, isInline);
|
||||
if (PR_FALSE==isInline)
|
||||
{
|
||||
nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
|
||||
if (!nodeAsText) {
|
||||
break;
|
||||
}
|
||||
// XXX: needs some logic to work for other leaf nodes besides text!
|
||||
}
|
||||
*aLeftNode = sibling;
|
||||
result = (*aLeftNode)->GetPreviousSibling(getter_AddRefs(sibling));
|
||||
}
|
||||
NS_ADDREF((*aLeftNode));
|
||||
// now do the right side
|
||||
result = aChild->GetNextSibling(getter_AddRefs(sibling));
|
||||
while ((NS_SUCCEEDED(result)) && sibling)
|
||||
{
|
||||
PRBool isInline;
|
||||
IsNodeInline(sibling, isInline);
|
||||
if (PR_FALSE==isInline)
|
||||
{
|
||||
nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
|
||||
if (!nodeAsText) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*aRightNode = sibling;
|
||||
result = (*aRightNode)->GetNextSibling(getter_AddRefs(sibling));
|
||||
}
|
||||
NS_ADDREF((*aRightNode));
|
||||
if (gNoisy) { printf("GetBlockSection returning %p %p\n",
|
||||
(*aLeftNode), (*aRightNode)); }
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEditor::GetBlockSectionsForRange(nsIDOMRange *aRange, nsISupportsArray *aSections)
|
||||
{
|
||||
if (!aRange || !aSections) {return NS_ERROR_NULL_POINTER;}
|
||||
|
||||
nsresult result;
|
||||
nsCOMPtr<nsIContentIterator>iter;
|
||||
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
|
||||
NS_GET_IID(nsIContentIterator), getter_AddRefs(iter));
|
||||
if ((NS_SUCCEEDED(result)) && iter)
|
||||
{
|
||||
nsCOMPtr<nsIDOMRange> lastRange;
|
||||
iter->Init(aRange);
|
||||
nsCOMPtr<nsIContent> currentContent;
|
||||
iter->CurrentNode(getter_AddRefs(currentContent));
|
||||
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>currentNode = do_QueryInterface(currentContent);
|
||||
if (currentNode)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> currentContentTag;
|
||||
currentContent->GetTag(*getter_AddRefs(currentContentTag));
|
||||
// <BR> divides block content ranges. We can achieve this by nulling out lastRange
|
||||
if (nsIEditProperty::br==currentContentTag.get())
|
||||
{
|
||||
lastRange = do_QueryInterface(nsnull);
|
||||
}
|
||||
else
|
||||
{
|
||||
PRBool isInlineOrText;
|
||||
result = IsNodeInline(currentNode, isInlineOrText);
|
||||
if (PR_FALSE==isInlineOrText)
|
||||
{
|
||||
PRUint16 nodeType;
|
||||
currentNode->GetNodeType(&nodeType);
|
||||
if (nsIDOMNode::TEXT_NODE == nodeType) {
|
||||
isInlineOrText = PR_TRUE;
|
||||
}
|
||||
}
|
||||
if (PR_TRUE==isInlineOrText)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>leftNode;
|
||||
nsCOMPtr<nsIDOMNode>rightNode;
|
||||
result = GetBlockSection(currentNode,
|
||||
getter_AddRefs(leftNode),
|
||||
getter_AddRefs(rightNode));
|
||||
if (gNoisy) {printf("currentNode %p has block content (%p,%p)\n", currentNode.get(), leftNode.get(), rightNode.get());}
|
||||
if ((NS_SUCCEEDED(result)) && leftNode && rightNode)
|
||||
{
|
||||
// add range to the list if it doesn't overlap with the previous range
|
||||
PRBool addRange=PR_TRUE;
|
||||
if (lastRange)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> lastStartNode;
|
||||
nsCOMPtr<nsIDOMElement> blockParentOfLastStartNode;
|
||||
lastRange->GetStartParent(getter_AddRefs(lastStartNode));
|
||||
result = GetBlockParent(lastStartNode, getter_AddRefs(blockParentOfLastStartNode));
|
||||
if ((NS_SUCCEEDED(result)) && blockParentOfLastStartNode)
|
||||
{
|
||||
if (gNoisy) {printf("lastStartNode %p has block parent %p\n", lastStartNode.get(), blockParentOfLastStartNode.get());}
|
||||
nsCOMPtr<nsIDOMElement> blockParentOfLeftNode;
|
||||
result = GetBlockParent(leftNode, getter_AddRefs(blockParentOfLeftNode));
|
||||
if ((NS_SUCCEEDED(result)) && blockParentOfLeftNode)
|
||||
{
|
||||
if (gNoisy) {printf("leftNode %p has block parent %p\n", leftNode.get(), blockParentOfLeftNode.get());}
|
||||
if (blockParentOfLastStartNode==blockParentOfLeftNode) {
|
||||
addRange = PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (PR_TRUE==addRange)
|
||||
{
|
||||
if (gNoisy) {printf("adding range, setting lastRange with start node %p\n", leftNode.get());}
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
result = nsComponentManager::CreateInstance(kCRangeCID, nsnull,
|
||||
NS_GET_IID(nsIDOMRange), getter_AddRefs(range));
|
||||
if ((NS_SUCCEEDED(result)) && range)
|
||||
{ // initialize the range
|
||||
range->SetStart(leftNode, 0);
|
||||
range->SetEnd(rightNode, 0);
|
||||
aSections->AppendElement(range);
|
||||
lastRange = do_QueryInterface(range);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* do not check result here, and especially do not return the result code.
|
||||
* we rely on iter->IsDone to tell us when the iteration is complete
|
||||
*/
|
||||
iter->Next();
|
||||
iter->CurrentNode(getter_AddRefs(currentContent));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEditor::IntermediateNodesAreInline(nsIDOMRange *aRange,
|
||||
nsIDOMNode *aStartNode,
|
||||
PRInt32 aStartOffset,
|
||||
nsIDOMNode *aEndNode,
|
||||
PRInt32 aEndOffset,
|
||||
PRBool &aResult)
|
||||
{
|
||||
aResult = PR_TRUE; // init out param. we assume the condition is true unless we find a node that violates it
|
||||
if (!aStartNode || !aEndNode || !aRange) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
nsCOMPtr<nsIContentIterator>iter;
|
||||
nsresult result;
|
||||
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
|
||||
NS_GET_IID(nsIContentIterator), getter_AddRefs(iter));
|
||||
//XXX: maybe CreateInstance is expensive, and I should keep around a static iter?
|
||||
// as long as this method can't be called recursively or re-entrantly!
|
||||
|
||||
if ((NS_SUCCEEDED(result)) && iter)
|
||||
{
|
||||
nsCOMPtr<nsIContent>startContent;
|
||||
startContent = do_QueryInterface(aStartNode);
|
||||
nsCOMPtr<nsIContent>endContent;
|
||||
endContent = do_QueryInterface(aEndNode);
|
||||
if (startContent && endContent)
|
||||
{
|
||||
iter->Init(aRange);
|
||||
nsCOMPtr<nsIContent> content;
|
||||
iter->CurrentNode(getter_AddRefs(content));
|
||||
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
||||
{
|
||||
if ((content.get() != startContent.get()) &&
|
||||
(content.get() != endContent.get()))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>currentNode;
|
||||
currentNode = do_QueryInterface(content);
|
||||
PRBool isInline=PR_FALSE;
|
||||
IsNodeInline(currentNode, isInline);
|
||||
if (PR_FALSE==isInline)
|
||||
{
|
||||
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
||||
nodeAsText = do_QueryInterface(currentNode);
|
||||
if (!nodeAsText) // text nodes don't count in this check, so ignore them
|
||||
{
|
||||
aResult = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* do not check result here, and especially do not return the result code.
|
||||
* we rely on iter->IsDone to tell us when the iteration is complete
|
||||
*/
|
||||
iter->Next();
|
||||
iter->CurrentNode(getter_AddRefs(content));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsEditor::GetPriorNode(nsIDOMNode *aParentNode,
|
||||
|
@ -4520,6 +4116,164 @@ nsEditor::HasSameBlockNodeParent(nsIDOMNode *aNode1, nsIDOMNode *aNode2)
|
|||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetBlockSection: return leftmost/rightmost nodes in aChild's block
|
||||
//
|
||||
nsresult
|
||||
nsEditor::GetBlockSection(nsIDOMNode *aChild,
|
||||
nsIDOMNode **aLeftNode,
|
||||
nsIDOMNode **aRightNode)
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
if (!aChild || !aLeftNode || !aRightNode) {return NS_ERROR_NULL_POINTER;}
|
||||
*aLeftNode = aChild;
|
||||
*aRightNode = aChild;
|
||||
|
||||
nsCOMPtr<nsIDOMNode>sibling;
|
||||
result = aChild->GetPreviousSibling(getter_AddRefs(sibling));
|
||||
while ((NS_SUCCEEDED(result)) && sibling)
|
||||
{
|
||||
PRBool isInline;
|
||||
IsNodeInline(sibling, isInline);
|
||||
if (PR_FALSE==isInline)
|
||||
{
|
||||
nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
|
||||
if (!nodeAsText) {
|
||||
break;
|
||||
}
|
||||
// XXX: needs some logic to work for other leaf nodes besides text!
|
||||
}
|
||||
*aLeftNode = sibling;
|
||||
result = (*aLeftNode)->GetPreviousSibling(getter_AddRefs(sibling));
|
||||
}
|
||||
NS_ADDREF((*aLeftNode));
|
||||
// now do the right side
|
||||
result = aChild->GetNextSibling(getter_AddRefs(sibling));
|
||||
while ((NS_SUCCEEDED(result)) && sibling)
|
||||
{
|
||||
PRBool isInline;
|
||||
IsNodeInline(sibling, isInline);
|
||||
if (PR_FALSE==isInline)
|
||||
{
|
||||
nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
|
||||
if (!nodeAsText) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*aRightNode = sibling;
|
||||
result = (*aRightNode)->GetNextSibling(getter_AddRefs(sibling));
|
||||
}
|
||||
NS_ADDREF((*aRightNode));
|
||||
if (gNoisy) { printf("GetBlockSection returning %p %p\n",
|
||||
(*aLeftNode), (*aRightNode)); }
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetBlockSectionsForRange: return list of block sections that intersect
|
||||
// this range
|
||||
nsresult
|
||||
nsEditor::GetBlockSectionsForRange(nsIDOMRange *aRange, nsISupportsArray *aSections)
|
||||
{
|
||||
if (!aRange || !aSections) {return NS_ERROR_NULL_POINTER;}
|
||||
|
||||
nsresult result;
|
||||
nsCOMPtr<nsIContentIterator>iter;
|
||||
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
|
||||
NS_GET_IID(nsIContentIterator), getter_AddRefs(iter));
|
||||
if ((NS_SUCCEEDED(result)) && iter)
|
||||
{
|
||||
nsCOMPtr<nsIDOMRange> lastRange;
|
||||
iter->Init(aRange);
|
||||
nsCOMPtr<nsIContent> currentContent;
|
||||
iter->CurrentNode(getter_AddRefs(currentContent));
|
||||
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>currentNode = do_QueryInterface(currentContent);
|
||||
if (currentNode)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> currentContentTag;
|
||||
currentContent->GetTag(*getter_AddRefs(currentContentTag));
|
||||
// <BR> divides block content ranges. We can achieve this by nulling out lastRange
|
||||
if (nsIEditProperty::br==currentContentTag.get())
|
||||
{
|
||||
lastRange = do_QueryInterface(nsnull);
|
||||
}
|
||||
else
|
||||
{
|
||||
PRBool isInlineOrText;
|
||||
result = IsNodeInline(currentNode, isInlineOrText);
|
||||
if (PR_FALSE==isInlineOrText)
|
||||
{
|
||||
PRUint16 nodeType;
|
||||
currentNode->GetNodeType(&nodeType);
|
||||
if (nsIDOMNode::TEXT_NODE == nodeType) {
|
||||
isInlineOrText = PR_TRUE;
|
||||
}
|
||||
}
|
||||
if (PR_TRUE==isInlineOrText)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>leftNode;
|
||||
nsCOMPtr<nsIDOMNode>rightNode;
|
||||
result = GetBlockSection(currentNode,
|
||||
getter_AddRefs(leftNode),
|
||||
getter_AddRefs(rightNode));
|
||||
if (gNoisy) {printf("currentNode %p has block content (%p,%p)\n", currentNode.get(), leftNode.get(), rightNode.get());}
|
||||
if ((NS_SUCCEEDED(result)) && leftNode && rightNode)
|
||||
{
|
||||
// add range to the list if it doesn't overlap with the previous range
|
||||
PRBool addRange=PR_TRUE;
|
||||
if (lastRange)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> lastStartNode;
|
||||
nsCOMPtr<nsIDOMElement> blockParentOfLastStartNode;
|
||||
lastRange->GetStartParent(getter_AddRefs(lastStartNode));
|
||||
blockParentOfLastStartNode = do_QueryInterface(GetBlockNodeParent(lastStartNode));
|
||||
if (blockParentOfLastStartNode)
|
||||
{
|
||||
if (gNoisy) {printf("lastStartNode %p has block parent %p\n", lastStartNode.get(), blockParentOfLastStartNode.get());}
|
||||
nsCOMPtr<nsIDOMElement> blockParentOfLeftNode;
|
||||
blockParentOfLeftNode = do_QueryInterface(GetBlockNodeParent(leftNode));
|
||||
if (blockParentOfLeftNode)
|
||||
{
|
||||
if (gNoisy) {printf("leftNode %p has block parent %p\n", leftNode.get(), blockParentOfLeftNode.get());}
|
||||
if (blockParentOfLastStartNode==blockParentOfLeftNode) {
|
||||
addRange = PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (PR_TRUE==addRange)
|
||||
{
|
||||
if (gNoisy) {printf("adding range, setting lastRange with start node %p\n", leftNode.get());}
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
result = nsComponentManager::CreateInstance(kCRangeCID, nsnull,
|
||||
NS_GET_IID(nsIDOMRange), getter_AddRefs(range));
|
||||
if ((NS_SUCCEEDED(result)) && range)
|
||||
{ // initialize the range
|
||||
range->SetStart(leftNode, 0);
|
||||
range->SetEnd(rightNode, 0);
|
||||
aSections->AppendElement(range);
|
||||
lastRange = do_QueryInterface(range);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* do not check result here, and especially do not return the result code.
|
||||
* we rely on iter->IsDone to tell us when the iteration is complete
|
||||
*/
|
||||
iter->Next();
|
||||
iter->CurrentNode(getter_AddRefs(currentContent));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// IsTextOrElementNode: true if node of dom type element or text
|
||||
//
|
||||
|
|
|
@ -263,10 +263,6 @@ public:
|
|||
|
||||
NS_IMETHOD DeleteNode(nsIDOMNode * aChild);
|
||||
|
||||
/* formatting within the dom tree */
|
||||
NS_IMETHOD InsertNoneditableTextNode(nsIDOMNode* aParent,
|
||||
PRInt32 aOffset,
|
||||
nsString& aStr);
|
||||
NS_IMETHOD MarkNodeDirty(nsIDOMNode* aNode);
|
||||
|
||||
|
||||
|
@ -303,7 +299,6 @@ public:
|
|||
public:
|
||||
|
||||
|
||||
NS_IMETHOD InsertTextImpl(const nsString& aStringToInsert);
|
||||
NS_IMETHOD JoeInsertTextImpl(const nsString& aStringToInsert,
|
||||
nsCOMPtr<nsIDOMNode> *aInOutNode,
|
||||
PRInt32 *aInOutOffset,
|
||||
|
@ -399,8 +394,6 @@ protected:
|
|||
*/
|
||||
NS_IMETHOD CreateTxnForRemoveStyleSheet(nsICSSStyleSheet* aSheet, RemoveStyleSheetTxn* *aTxn);
|
||||
|
||||
NS_IMETHOD PrepareToInsertText(nsCOMPtr<nsIDOMCharacterData> *aOutTextNode, PRInt32 *aOutOffset);
|
||||
|
||||
NS_IMETHOD DeleteText(nsIDOMCharacterData *aElement,
|
||||
PRUint32 aOffset,
|
||||
PRUint32 aLength);
|
||||
|
@ -529,58 +522,6 @@ public:
|
|||
/** This version is for exposure to JavaScript */
|
||||
NS_IMETHOD NodeIsBlock(nsIDOMNode *aNode, PRBool &aIsBlock);
|
||||
|
||||
/** returns the closest block parent of aNode, not including aNode itself.
|
||||
* can return null, for example if aNode is in a document fragment.
|
||||
* @param aNode The node whose parent we seek.
|
||||
* @param aBlockParent [OUT] The block parent, if any.
|
||||
* @return a success value unless an unexpected error occurs.
|
||||
*/
|
||||
static nsresult GetBlockParent(nsIDOMNode *aNode,
|
||||
nsIDOMElement **aBlockParent);
|
||||
|
||||
/** Determines the bounding nodes for the block section containing aNode.
|
||||
* The calculation is based on some nodes intrinsically being block elements
|
||||
* acording to HTML. Style sheets are not considered in this calculation.
|
||||
* <BR> tags separate block content sections. So the HTML markup:
|
||||
* <PRE>
|
||||
* <P>text1<BR>text2<B>text3</B></P>
|
||||
* </PRE>
|
||||
* contains two block content sections. The first has the text node "text1"
|
||||
* for both endpoints. The second has "text2" as the left endpoint and
|
||||
* "text3" as the right endpoint.
|
||||
* Notice that offsets aren't required, only leaf nodes. Offsets are implicit.
|
||||
*
|
||||
* @param aNode the block content returned includes aNode
|
||||
* @param aLeftNode [OUT] the left endpoint of the block content containing aNode
|
||||
* @param aRightNode [OUT] the right endpoint of the block content containing aNode
|
||||
*
|
||||
*/
|
||||
static nsresult GetBlockSection(nsIDOMNode *aNode,
|
||||
nsIDOMNode **aLeftNode,
|
||||
nsIDOMNode **aRightNode);
|
||||
|
||||
/** Compute the set of block sections in a given range.
|
||||
* A block section is the set of (leftNode, rightNode) pairs given
|
||||
* by GetBlockSection. The set is computed by computing the
|
||||
* block section for every leaf node in the range and throwing
|
||||
* out duplicates.
|
||||
*
|
||||
* @param aRange The range to compute block sections for.
|
||||
* @param aSections Allocated storage for the resulting set, stored as nsIDOMRanges.
|
||||
*/
|
||||
static nsresult GetBlockSectionsForRange(nsIDOMRange *aRange,
|
||||
nsISupportsArray *aSections);
|
||||
|
||||
/** returns PR_TRUE in out-param aResult if all nodes between (aStartNode, aStartOffset)
|
||||
* and (aEndNode, aEndOffset) are inline as defined by HTML DTD.
|
||||
*/
|
||||
static nsresult IntermediateNodesAreInline(nsIDOMRange *aRange,
|
||||
nsIDOMNode *aStartNode,
|
||||
PRInt32 aStartOffset,
|
||||
nsIDOMNode *aEndNode,
|
||||
PRInt32 aEndOffset,
|
||||
PRBool &aResult);
|
||||
|
||||
/** returns the number of things inside aNode in the out-param aCount.
|
||||
* @param aNode is the node to get the length of.
|
||||
* If aNode is text, returns number of characters.
|
||||
|
@ -690,6 +631,39 @@ public:
|
|||
static PRBool IsInlineNode(nsIDOMNode *aNode);
|
||||
static nsCOMPtr<nsIDOMNode> GetBlockNodeParent(nsIDOMNode *aNode);
|
||||
static PRBool HasSameBlockNodeParent(nsIDOMNode *aNode1, nsIDOMNode *aNode2);
|
||||
/** Determines the bounding nodes for the block section containing aNode.
|
||||
* The calculation is based on some nodes intrinsically being block elements
|
||||
* acording to HTML. Style sheets are not considered in this calculation.
|
||||
* <BR> tags separate block content sections. So the HTML markup:
|
||||
* <PRE>
|
||||
* <P>text1<BR>text2<B>text3</B></P>
|
||||
* </PRE>
|
||||
* contains two block content sections. The first has the text node "text1"
|
||||
* for both endpoints. The second has "text2" as the left endpoint and
|
||||
* "text3" as the right endpoint.
|
||||
* Notice that offsets aren't required, only leaf nodes. Offsets are implicit.
|
||||
*
|
||||
* @param aNode the block content returned includes aNode
|
||||
* @param aLeftNode [OUT] the left endpoint of the block content containing aNode
|
||||
* @param aRightNode [OUT] the right endpoint of the block content containing aNode
|
||||
*
|
||||
*/
|
||||
static nsresult GetBlockSection(nsIDOMNode *aNode,
|
||||
nsIDOMNode **aLeftNode,
|
||||
nsIDOMNode **aRightNode);
|
||||
|
||||
/** Compute the set of block sections in a given range.
|
||||
* A block section is the set of (leftNode, rightNode) pairs given
|
||||
* by GetBlockSection. The set is computed by computing the
|
||||
* block section for every leaf node in the range and throwing
|
||||
* out duplicates.
|
||||
*
|
||||
* @param aRange The range to compute block sections for.
|
||||
* @param aSections Allocated storage for the resulting set, stored as nsIDOMRanges.
|
||||
*/
|
||||
static nsresult GetBlockSectionsForRange(nsIDOMRange *aRange,
|
||||
nsISupportsArray *aSections);
|
||||
|
||||
|
||||
static PRBool IsTextOrElementNode(nsIDOMNode *aNode);
|
||||
static PRBool IsTextNode(nsIDOMNode *aNode);
|
||||
|
|
|
@ -209,6 +209,10 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
|||
res = AdjustSpecialBreaks();
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// merge any adjacent text nodes
|
||||
res = mEditor->CollapseAdjacentTextNodes(mDocChangeRange);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// adjust whitespace for insert text and delete actions
|
||||
if ((action == nsEditor::kOpInsertText) ||
|
||||
(action == nsEditor::kOpInsertIMEText) ||
|
||||
|
@ -230,8 +234,6 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
|||
res = RemoveEmptyNodes();
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
/* I'll move to this code in M15. For now being very conservative with changes
|
||||
|
||||
// adjust selection for insert text and delete actions
|
||||
if ((action == nsEditor::kOpInsertText) ||
|
||||
(action == nsEditor::kOpInsertIMEText) ||
|
||||
|
@ -240,20 +242,8 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
|||
res = AdjustSelection(selection, aDirection);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// adjust selection unless it was an inline style manipulation
|
||||
// see above commented out code: we're just being safe for now
|
||||
// with the minimal change to fix selection problem when removing
|
||||
// link property
|
||||
if ((action != nsEditor::kOpSetTextProperty) &&
|
||||
(action != nsEditor::kOpRemoveTextProperty))
|
||||
{
|
||||
res = AdjustSelection(selection, aDirection);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
|
||||
// detect empty doc
|
||||
res = CreateBogusNodeIfNeeded(selection);
|
||||
|
||||
|
@ -295,7 +285,6 @@ nsHTMLEditRules::WillDoAction(nsIDOMSelection *aSelection,
|
|||
aHandled,
|
||||
info->inString,
|
||||
info->outString,
|
||||
info->typeInState,
|
||||
info->maxLength);
|
||||
case kInsertBreak:
|
||||
return WillInsertBreak(aSelection, aCancel, aHandled);
|
||||
|
@ -342,7 +331,6 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
|
|||
PRBool *aHandled,
|
||||
const nsString *inString,
|
||||
nsString *outString,
|
||||
TypeInState typeInState,
|
||||
PRInt32 aMaxLength)
|
||||
{
|
||||
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
||||
|
@ -393,44 +381,26 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
|
|||
if (!mEditor->IsTextNode(selNode) && !mEditor->CanContainTag(selNode, textTag))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// take care of typeinstate issues
|
||||
if (typeInState.IsAnySet())
|
||||
{ // for every property that is set, insert a new inline style node
|
||||
res = CreateStyleForInsertText(aSelection, typeInState);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// refresh the (collapsed) selection location
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
// identify the block
|
||||
nsCOMPtr<nsIDOMNode> blockParent;
|
||||
|
||||
if (nsEditor::IsBlockNode(selNode))
|
||||
blockParent = selNode;
|
||||
else
|
||||
blockParent = mEditor->GetBlockNodeParent(selNode);
|
||||
if (!blockParent) return NS_ERROR_FAILURE;
|
||||
|
||||
PRBool bCancel;
|
||||
nsString theString(*inString); // copy instring for now
|
||||
if(aAction == kInsertTextIME)
|
||||
// we need to get the doc
|
||||
nsCOMPtr<nsIDOMDocument>doc;
|
||||
res = mEditor->GetDocument(getter_AddRefs(doc));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!doc) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// for every property that is set, insert a new inline style node
|
||||
res = CreateStyleForInsertText(aSelection, doc);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// refresh the (collapsed) selection location
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
if (aAction == kInsertTextIME)
|
||||
{
|
||||
// special case for IME. We need this to :
|
||||
// a) handle null strings, which are meaningful for IME
|
||||
// b) prevent the string from being broken into substrings,
|
||||
// which can happen in non-IME processing below.
|
||||
// I should probably convert runs of spaces and tabs here as well
|
||||
res = DoTextInsertion(aSelection, &bCancel, &theString, typeInState);
|
||||
res = mEditor->JoeInsertTextImpl(*inString, &selNode, &selOffset, doc);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
else // aAction == kInsertText
|
||||
{
|
||||
// we need to get the doc
|
||||
nsCOMPtr<nsIDOMDocument>doc;
|
||||
res = mEditor->GetDocument(getter_AddRefs(doc));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!doc) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// find where we are
|
||||
nsCOMPtr<nsIDOMNode> curNode = selNode;
|
||||
PRInt32 curOffset = selOffset;
|
||||
|
@ -449,9 +419,10 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
|
|||
|
||||
// dont spaz my selection in subtransactions
|
||||
nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
|
||||
nsAutoString partialString;
|
||||
nsSubsumeStr subStr;
|
||||
const PRUnichar *unicodeBuf = inString->GetUnicode();
|
||||
nsCOMPtr<nsIDOMNode> unused;
|
||||
PRInt32 pos;
|
||||
PRInt32 pos = 0;
|
||||
|
||||
// for efficiency, break out the pre case seperately. This is because
|
||||
// its a lot cheaper to search the input string for only newlines than
|
||||
|
@ -459,22 +430,36 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
|
|||
if (isPRE)
|
||||
{
|
||||
char newlineChar = '\n';
|
||||
while (theString.Length())
|
||||
while (unicodeBuf && (pos != -1) && (pos < inString->Length()))
|
||||
{
|
||||
pos = theString.FindChar(newlineChar);
|
||||
// if first char is newline, then use just it
|
||||
if (pos == 0) pos = 1;
|
||||
if (pos == -1) pos = theString.Length();
|
||||
theString.Left(partialString, pos);
|
||||
theString.Cut(0, pos);
|
||||
// is it a return?
|
||||
if (partialString.Equals("\n"))
|
||||
PRInt32 oldPos = pos;
|
||||
PRInt32 subStrLen;
|
||||
pos = inString->FindChar(newlineChar, PR_FALSE, oldPos);
|
||||
|
||||
if (pos != -1)
|
||||
{
|
||||
res = mEditor->JoeCreateBR(&curNode, &curOffset, &unused, nsIEditor::eNone);
|
||||
subStrLen = pos - oldPos;
|
||||
// if first char is newline, then use just it
|
||||
if (subStrLen == 0)
|
||||
subStrLen = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(partialString, &curNode, &curOffset, doc);
|
||||
subStrLen = inString->Length() - oldPos;
|
||||
pos = inString->Length();
|
||||
}
|
||||
|
||||
subStr.Subsume((PRUnichar*)&unicodeBuf[oldPos], PR_FALSE, subStrLen);
|
||||
|
||||
// is it a return?
|
||||
if (subStr.Equals("\n"))
|
||||
{
|
||||
res = mEditor->JoeCreateBR(&curNode, &curOffset, &unused, nsIEditor::eNone);
|
||||
pos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(subStr, &curNode, &curOffset, doc);
|
||||
}
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
@ -483,28 +468,42 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
|
|||
{
|
||||
char specialChars[] = {'\t','\n',0};
|
||||
nsAutoString tabString = " ";
|
||||
while (theString.Length())
|
||||
while (unicodeBuf && (pos != -1) && (pos < inString->Length()))
|
||||
{
|
||||
pos = theString.FindCharInSet(specialChars);
|
||||
// if first char is special, then use just it
|
||||
if (pos == 0) pos = 1;
|
||||
if (pos == -1) pos = theString.Length();
|
||||
theString.Left(partialString, pos);
|
||||
theString.Cut(0, pos);
|
||||
// is it a tab?
|
||||
if (partialString.Equals("\t"))
|
||||
PRInt32 oldPos = pos;
|
||||
PRInt32 subStrLen;
|
||||
pos = inString->FindCharInSet(specialChars, oldPos);
|
||||
|
||||
if (pos != -1)
|
||||
{
|
||||
partialString = " ";
|
||||
res = mEditor->JoeInsertTextImpl(tabString, &curNode, &curOffset, doc);
|
||||
}
|
||||
// is it a return?
|
||||
else if (partialString.Equals("\n"))
|
||||
{
|
||||
res = mEditor->JoeCreateBR(&curNode, &curOffset, &unused, nsIEditor::eNone);
|
||||
subStrLen = pos - oldPos;
|
||||
// if first char is newline, then use just it
|
||||
if (subStrLen == 0)
|
||||
subStrLen = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(partialString, &curNode, &curOffset, doc);
|
||||
subStrLen = inString->Length() - oldPos;
|
||||
pos = inString->Length();
|
||||
}
|
||||
|
||||
subStr.Subsume((PRUnichar*)&unicodeBuf[oldPos], PR_FALSE, subStrLen);
|
||||
|
||||
// is it a tab?
|
||||
if (subStr.Equals("\t"))
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(tabString, &curNode, &curOffset, doc);
|
||||
pos++;
|
||||
}
|
||||
// is it a return?
|
||||
else if (subStr.Equals("\n"))
|
||||
{
|
||||
res = mEditor->JoeCreateBR(&curNode, &curOffset, &unused, nsIEditor::eNone);
|
||||
pos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(subStr, &curNode, &curOffset, doc);
|
||||
}
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
@ -683,7 +682,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
if (!offset && (aAction == nsIEditor::ePrevious))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> priorNode;
|
||||
res = GetPriorHTMLNode(node, &priorNode);
|
||||
res = mEditor->GetPriorHTMLNode(node, &priorNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// if there is no prior node then cancel the deletion
|
||||
|
@ -705,7 +704,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
// we did something, so lets say so.
|
||||
*aHandled = PR_TRUE;
|
||||
// get new prior node
|
||||
res = GetPriorHTMLNode(node, &priorNode);
|
||||
res = mEditor->GetPriorHTMLNode(node, &priorNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// are they in same block?
|
||||
if (mEditor->HasSameBlockNodeParent(node, priorNode))
|
||||
|
@ -782,7 +781,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
&& (aAction == nsIEditor::eNext))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> nextNode;
|
||||
res = GetNextHTMLNode(node, &nextNode);
|
||||
res = mEditor->GetNextHTMLNode(node, &nextNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// if there is no next node, or it's not in the body, then cancel the deletion
|
||||
|
@ -804,7 +803,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
// we did something, so lets say so.
|
||||
*aHandled = PR_TRUE;
|
||||
// get new next node
|
||||
res = GetNextHTMLNode(node, &nextNode);
|
||||
res = mEditor->GetNextHTMLNode(node, &nextNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// are they in same block?
|
||||
if (mEditor->HasSameBlockNodeParent(node, nextNode))
|
||||
|
@ -892,9 +891,9 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
if (bIsEmptyNode && !mEditor->IsTableElement(node))
|
||||
nodeToDelete = node;
|
||||
else if (aAction == nsIEditor::ePrevious)
|
||||
res = GetPriorHTMLNode(node, offset, &nodeToDelete);
|
||||
res = mEditor->GetPriorHTMLNode(node, offset, &nodeToDelete);
|
||||
else if (aAction == nsIEditor::eNext)
|
||||
res = GetNextHTMLNode(node, offset, &nodeToDelete);
|
||||
res = mEditor->GetNextHTMLNode(node, offset, &nodeToDelete);
|
||||
else
|
||||
return NS_OK;
|
||||
|
||||
|
@ -925,7 +924,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
if (nsHTMLEditUtils::IsMozBR(nodeToDelete))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
res = GetPriorHTMLNode(nodeToDelete, &brNode);
|
||||
res = mEditor->GetPriorHTMLNode(nodeToDelete, &brNode);
|
||||
if (nsHTMLEditUtils::IsBreak(brNode))
|
||||
{
|
||||
// is brNode also a descendant of same block?
|
||||
|
@ -1695,6 +1694,69 @@ nsHTMLEditRules::WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel, PRBoo
|
|||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// CreateStyleForInsertText: take care of clearing and setting appropriate
|
||||
// style nodes for text insertion.
|
||||
//
|
||||
//
|
||||
nsresult
|
||||
nsHTMLEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, nsIDOMDocument *aDoc)
|
||||
{
|
||||
if (!aSelection || !aDoc) return NS_ERROR_NULL_POINTER;
|
||||
if (!mEditor->mTypeInState) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> node;
|
||||
PRInt32 offset;
|
||||
nsresult res = mEditor->GetStartNodeAndOffset(aSelection, &node, &offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
PropItem *item = nsnull;
|
||||
|
||||
// process clearing any styles first
|
||||
mEditor->mTypeInState->ProcessClearProperty(&item);
|
||||
while (item)
|
||||
{
|
||||
res = mEditor->SplitStyleAbovePoint(&node, &offset, item->tag, &item->attr);
|
||||
if (NS_FAILED(res)) return res;
|
||||
mEditor->mTypeInState->ProcessClearProperty(&item);
|
||||
}
|
||||
|
||||
// then process setting any styles
|
||||
mEditor->mTypeInState->ProcessSetProperty(&item);
|
||||
|
||||
if (item) // we have at least one style to add; make a
|
||||
{ // new text node to insert style nodes above.
|
||||
if (mEditor->IsTextNode(node))
|
||||
{
|
||||
// if we are in a text node, split it
|
||||
res = mEditor->SplitNodeDeep(node, node, offset, &offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
nsCOMPtr<nsIDOMNode> tmp;
|
||||
node->GetParentNode(getter_AddRefs(tmp));
|
||||
node = tmp;
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
nsCOMPtr<nsIDOMText> nodeAsText;
|
||||
res = aDoc->CreateTextNode("", getter_AddRefs(nodeAsText));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!nodeAsText) return NS_ERROR_NULL_POINTER;
|
||||
newNode = do_QueryInterface(nodeAsText);
|
||||
res = mEditor->InsertNode(newNode, node, offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
node = newNode;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
while (item)
|
||||
{
|
||||
res = mEditor->SetInlinePropertyOnNode(node, item->tag, &item->attr, &item->value);
|
||||
if (NS_FAILED(res)) return res;
|
||||
mEditor->mTypeInState->ProcessSetProperty(&item);
|
||||
}
|
||||
|
||||
return aSelection->Collapse(node, offset);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// IsEmptyBlock: figure out if aNode is (or is inside) an empty block.
|
||||
// A block can have children and still be considered empty,
|
||||
|
@ -2023,9 +2085,9 @@ nsHTMLEditRules::AlignTableCellContents(nsIDOMNode *aNode, const nsString *align
|
|||
nsresult res;
|
||||
nsCOMPtr <nsIDOMNode> firstChild, lastChild, divNode;
|
||||
|
||||
res = GetFirstEditableChild(aNode, &firstChild);
|
||||
res = mEditor->GetFirstEditableChild(aNode, &firstChild);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = GetLastEditableChild(aNode, &lastChild);
|
||||
res = mEditor->GetLastEditableChild(aNode, &lastChild);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!firstChild)
|
||||
{
|
||||
|
@ -2056,7 +2118,7 @@ nsHTMLEditRules::AlignTableCellContents(nsIDOMNode *aNode, const nsString *align
|
|||
{
|
||||
res = mEditor->MoveNode(lastChild, divNode, 0);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = GetLastEditableChild(aNode, &lastChild);
|
||||
res = mEditor->GetLastEditableChild(aNode, &lastChild);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
|
@ -2100,13 +2162,13 @@ nsHTMLEditRules::GetTableContent(nsIDOMNode *aNode, nsCOMPtr<nsISupportsArray> *
|
|||
if (mEditor->IsTableCell(node))
|
||||
{
|
||||
nsCOMPtr <nsIDOMNode> child, tmp;
|
||||
res = GetFirstEditableChild(node, &child);
|
||||
res = mEditor->GetFirstEditableChild(node, &child);
|
||||
if (NS_FAILED(res)) return res;
|
||||
while (child)
|
||||
{
|
||||
isupports = do_QueryInterface(child);
|
||||
(*outArrayOfNodes)->AppendElement(isupports);
|
||||
GetNextHTMLSibling(child, &tmp);
|
||||
mEditor->GetNextHTMLSibling(child, &tmp);
|
||||
child = tmp;
|
||||
}
|
||||
}
|
||||
|
@ -2208,7 +2270,7 @@ nsHTMLEditRules::AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *
|
|||
if (nodeAsText && aOffset) return PR_FALSE; // there are chars in front of us
|
||||
|
||||
nsCOMPtr<nsIDOMNode> priorNode;
|
||||
nsresult res = GetPriorHTMLNode(aNode, aOffset, &priorNode);
|
||||
nsresult res = mEditor->GetPriorHTMLNode(aNode, aOffset, &priorNode);
|
||||
if (NS_FAILED(res)) return PR_TRUE;
|
||||
if (!priorNode) return PR_TRUE;
|
||||
nsCOMPtr<nsIDOMNode> blockParent = mEditor->GetBlockNodeParent(priorNode);
|
||||
|
@ -2231,7 +2293,7 @@ nsHTMLEditRules::AtEndOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aB
|
|||
if ((PRInt32)strLength > aOffset) return PR_FALSE; // there are chars in after us
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> nextNode;
|
||||
nsresult res = GetNextHTMLNode(aNode, aOffset, &nextNode);
|
||||
nsresult res = mEditor->GetNextHTMLNode(aNode, aOffset, &nextNode);
|
||||
if (NS_FAILED(res)) return PR_TRUE;
|
||||
if (!nextNode) return PR_TRUE;
|
||||
nsCOMPtr<nsIDOMNode> blockParent = mEditor->GetBlockNodeParent(nextNode);
|
||||
|
@ -2724,7 +2786,7 @@ nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection,
|
|||
|
||||
// if the leftand heading is empty, put a mozbr in it
|
||||
nsCOMPtr<nsIDOMNode> prevItem;
|
||||
GetPriorHTMLSibling(aHeader, &prevItem);
|
||||
mEditor->GetPriorHTMLSibling(aHeader, &prevItem);
|
||||
if (prevItem && nsHTMLEditUtils::IsHeader(prevItem))
|
||||
{
|
||||
PRBool bIsEmptyNode;
|
||||
|
@ -2749,7 +2811,7 @@ nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection,
|
|||
// layout tells the caret to blink in a weird place
|
||||
// if we dont place a break after the header.
|
||||
nsCOMPtr<nsIDOMNode> sibling;
|
||||
res = GetNextHTMLSibling(headerParent, offset+1, &sibling);
|
||||
res = mEditor->GetNextHTMLSibling(headerParent, offset+1, &sibling);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!sibling || !nsHTMLEditUtils::IsBreak(sibling))
|
||||
{
|
||||
|
@ -2801,7 +2863,7 @@ nsHTMLEditRules::ReturnInParagraph(nsIDOMSelection *aSelection,
|
|||
if (!aOffset)
|
||||
{
|
||||
// is there a BR prior to it?
|
||||
GetPriorHTMLSibling(aNode, &sibling);
|
||||
mEditor->GetPriorHTMLSibling(aNode, &sibling);
|
||||
if (!sibling)
|
||||
{
|
||||
// no previous sib, so
|
||||
|
@ -2829,7 +2891,7 @@ nsHTMLEditRules::ReturnInParagraph(nsIDOMSelection *aSelection,
|
|||
if (aOffset == (PRInt32)strLength)
|
||||
{
|
||||
// is there a BR after to it?
|
||||
res = GetNextHTMLSibling(aNode, &sibling);
|
||||
res = mEditor->GetNextHTMLSibling(aNode, &sibling);
|
||||
if (!sibling)
|
||||
{
|
||||
// no next sib, so
|
||||
|
@ -2862,13 +2924,13 @@ nsHTMLEditRules::ReturnInParagraph(nsIDOMSelection *aSelection,
|
|||
// not in a text node.
|
||||
// is there a BR prior to it?
|
||||
nsCOMPtr<nsIDOMNode> nearNode;
|
||||
res = GetPriorHTMLNode(aNode, aOffset, &nearNode);
|
||||
res = mEditor->GetPriorHTMLNode(aNode, aOffset, &nearNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!nearNode || !nsHTMLEditUtils::IsBreak(nearNode)
|
||||
|| nsHTMLEditUtils::HasMozAttr(nearNode))
|
||||
{
|
||||
// is there a BR after to it?
|
||||
res = GetNextHTMLNode(aNode, aOffset, &nearNode);
|
||||
res = mEditor->GetNextHTMLNode(aNode, aOffset, &nearNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!nearNode || !nsHTMLEditUtils::IsBreak(nearNode)
|
||||
|| nsHTMLEditUtils::HasMozAttr(nearNode))
|
||||
|
@ -2928,7 +2990,7 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,
|
|||
|
||||
// are we the last list item in the list?
|
||||
PRBool bIsLast;
|
||||
res = IsLastEditableChild(aListItem, &bIsLast);
|
||||
res = mEditor->IsLastEditableChild(aListItem, &bIsLast);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!bIsLast)
|
||||
{
|
||||
|
@ -2971,7 +3033,7 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,
|
|||
// extra inclusive, I have to manually detect certain list items that
|
||||
// may be left empty.
|
||||
nsCOMPtr<nsIDOMNode> prevItem;
|
||||
GetPriorHTMLSibling(aListItem, &prevItem);
|
||||
mEditor->GetPriorHTMLSibling(aListItem, &prevItem);
|
||||
if (prevItem && nsHTMLEditUtils::IsListItem(prevItem))
|
||||
{
|
||||
PRBool bIsEmptyNode;
|
||||
|
@ -3322,9 +3384,9 @@ nsHTMLEditRules::JoinNodesSmart( nsIDOMNode *aNodeLeft,
|
|||
{
|
||||
// remember the last left child, and firt right child
|
||||
nsCOMPtr<nsIDOMNode> lastLeft, firstRight;
|
||||
res = GetLastEditableChild(aNodeLeft, &lastLeft);
|
||||
res = mEditor->GetLastEditableChild(aNodeLeft, &lastLeft);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = GetFirstEditableChild(aNodeRight, &firstRight);
|
||||
res = mEditor->GetFirstEditableChild(aNodeRight, &firstRight);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// for list items, divs, etc, merge smart
|
||||
|
@ -3555,7 +3617,7 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
|
|||
// 4) that br is the last editable node in it's block
|
||||
|
||||
nsCOMPtr<nsIDOMNode> nearNode;
|
||||
res = GetPriorHTMLNode(selNode, selOffset, &nearNode);
|
||||
res = mEditor->GetPriorHTMLNode(selNode, selOffset, &nearNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!nearNode) return res;
|
||||
|
||||
|
@ -3570,7 +3632,7 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
|
|||
&& !nsHTMLEditUtils::IsMozBR(nearNode))
|
||||
{
|
||||
PRBool bIsLast;
|
||||
res = IsLastEditableChild(nearNode, &bIsLast);
|
||||
res = mEditor->IsLastEditableChild(nearNode, &bIsLast);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (bIsLast)
|
||||
{
|
||||
|
@ -3594,9 +3656,9 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
|
|||
// <body> text<br> <ol><li>list item</li></ol></body> )
|
||||
// in this case we also need moz-br.
|
||||
nsCOMPtr<nsIDOMNode> nextNode;
|
||||
res = GetNextHTMLNode(nearNode, &nextNode);
|
||||
res = mEditor->GetNextHTMLNode(nearNode, &nextNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = GetNextHTMLSibling(nearNode, &nextNode);
|
||||
res = mEditor->GetNextHTMLSibling(nearNode, &nextNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (nextNode && mEditor->IsBlockNode(nextNode))
|
||||
{
|
||||
|
@ -3617,12 +3679,12 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
|
|||
}
|
||||
|
||||
// we aren't in a textnode: are we adjacent to a break or an image?
|
||||
res = GetPriorHTMLSibling(selNode, selOffset, &nearNode);
|
||||
res = mEditor->GetPriorHTMLSibling(selNode, selOffset, &nearNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (nearNode && (nsHTMLEditUtils::IsBreak(nearNode)
|
||||
|| nsHTMLEditUtils::IsImage(nearNode)))
|
||||
return NS_OK; // this is a good place for the caret to be
|
||||
res = GetNextHTMLSibling(selNode, selOffset, &nearNode);
|
||||
res = mEditor->GetNextHTMLSibling(selNode, selOffset, &nearNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (nearNode && (nsHTMLEditUtils::IsBreak(nearNode)
|
||||
|| nsHTMLEditUtils::IsImage(nearNode)))
|
||||
|
@ -3668,9 +3730,9 @@ nsHTMLEditRules::FindNearSelectableNode(nsIDOMNode *aSelNode,
|
|||
|
||||
nsCOMPtr<nsIDOMNode> nearNode, curNode;
|
||||
if (aDirection == nsIEditor::ePrevious)
|
||||
res = GetPriorHTMLNode(aSelNode, aSelOffset, &nearNode);
|
||||
res = mEditor->GetPriorHTMLNode(aSelNode, aSelOffset, &nearNode);
|
||||
else
|
||||
res = GetNextHTMLNode(aSelNode, aSelOffset, &nearNode);
|
||||
res = mEditor->GetNextHTMLNode(aSelNode, aSelOffset, &nearNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// scan in the right direction until we find an eligible text node,
|
||||
|
@ -3685,9 +3747,9 @@ nsHTMLEditRules::FindNearSelectableNode(nsIDOMNode *aSelNode,
|
|||
|
||||
curNode = nearNode;
|
||||
if (aDirection == nsIEditor::ePrevious)
|
||||
res = GetPriorHTMLNode(curNode, &nearNode);
|
||||
res = mEditor->GetPriorHTMLNode(curNode, &nearNode);
|
||||
else
|
||||
res = GetNextHTMLNode(curNode, &nearNode);
|
||||
res = mEditor->GetNextHTMLNode(curNode, &nearNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
|
@ -4011,11 +4073,11 @@ nsHTMLEditRules::PopListItem(nsIDOMNode *aListItem, PRBool *aOutOfList)
|
|||
if (NS_FAILED(res)) return res;
|
||||
|
||||
PRBool bIsFirstListItem;
|
||||
res = IsFirstEditableChild(curNode, &bIsFirstListItem);
|
||||
res = mEditor->IsFirstEditableChild(curNode, &bIsFirstListItem);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
PRBool bIsLastListItem;
|
||||
res = IsLastEditableChild(curNode, &bIsLastListItem);
|
||||
res = mEditor->IsLastEditableChild(curNode, &bIsLastListItem);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
if (!bIsFirstListItem && !bIsLastListItem)
|
||||
|
@ -4036,7 +4098,7 @@ nsHTMLEditRules::PopListItem(nsIDOMNode *aListItem, PRBool *aOutOfList)
|
|||
&& nsHTMLEditUtils::IsListItem(curNode))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> lastChild;
|
||||
res = GetLastEditableChild(curNode, &lastChild);
|
||||
res = mEditor->GetLastEditableChild(curNode, &lastChild);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->RemoveContainer(curNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
|
|
@ -85,7 +85,6 @@ protected:
|
|||
PRBool *aHandled,
|
||||
const nsString *inString,
|
||||
nsString *outString,
|
||||
TypeInState typeInState,
|
||||
PRInt32 aMaxLength);
|
||||
nsresult WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillDeleteSelection(nsIDOMSelection *aSelection, nsIEditor::EDirection aAction,
|
||||
|
@ -107,6 +106,7 @@ protected:
|
|||
nsresult ReturnInParagraph(nsIDOMSelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult ReturnInListItem(nsIDOMSelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset);
|
||||
|
||||
nsresult CreateStyleForInsertText(nsIDOMSelection *aSelection, nsIDOMDocument *aDoc);
|
||||
nsresult IsEmptyBlock(nsIDOMNode *aNode,
|
||||
PRBool *outIsEmptyBlock,
|
||||
PRBool aMozBRDoesntCount = PR_FALSE,
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -281,12 +281,30 @@ public:
|
|||
/** make the given selection span the entire document */
|
||||
NS_IMETHOD SelectEntireDocument(nsIDOMSelection *aSelection);
|
||||
|
||||
/** join together any afjacent editable text nodes in the range */
|
||||
NS_IMETHOD CollapseAdjacentTextNodes(nsIDOMRange *aInRange);
|
||||
|
||||
/* ------------ nsICSSLoaderObserver -------------- */
|
||||
NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet*aSheet, PRBool aNotify);
|
||||
|
||||
/* ------------ Utility Routines, not part of public API -------------- */
|
||||
NS_IMETHOD GetBodyStyleContext(nsIStyleContext** aStyleContext);
|
||||
|
||||
/** returns the absolute position of the end points of aSelection
|
||||
* in the document as a text stream.
|
||||
*/
|
||||
nsresult GetTextSelectionOffsets(nsIDOMSelection *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();
|
||||
|
@ -306,8 +324,6 @@ protected:
|
|||
*/
|
||||
NS_IMETHOD GetLayoutObject(nsIDOMNode *aInNode, nsISupports **aOutLayoutObject);
|
||||
|
||||
NS_IMETHOD CollapseAdjacentTextNodes(nsIDOMSelection *aInSelection);
|
||||
|
||||
NS_IMETHOD DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNode> &parentSelectedNode, PRInt32& offsetOfNewNode);
|
||||
|
||||
/* StyleSheet load callback */
|
||||
|
@ -325,10 +341,6 @@ protected:
|
|||
void CacheInlineStyles(nsIDOMNode *aNode);
|
||||
void ClearInlineStylesCache();
|
||||
|
||||
// typing state getters
|
||||
NS_IMETHOD GetTypingState(nsIAtom *aProperty, PRBool &aPropIsSet, PRBool &aSetting);
|
||||
NS_IMETHOD GetTypingStateValue(nsIAtom *aProperty, PRBool &aPropIsSet, nsString &aValue);
|
||||
|
||||
// key event helpers
|
||||
NS_IMETHOD TabInTable(PRBool inIsShift, PRBool *outHandled);
|
||||
NS_IMETHOD CreateBR(nsIDOMNode *aNode, PRInt32 aOffset,
|
||||
|
@ -371,37 +383,10 @@ protected:
|
|||
// failed to set selection to some other content in the document
|
||||
NS_IMETHOD SetSelectionAtDocumentStart(nsIDOMSelection *aSelection);
|
||||
|
||||
|
||||
// End of Table Editing utilities
|
||||
|
||||
|
||||
NS_IMETHOD ReParentContentOfNode(nsIDOMNode *aNode,
|
||||
nsString &aParentTag,
|
||||
BlockTransformationType aTranformation);
|
||||
|
||||
NS_IMETHOD ReParentBlockContent(nsIDOMNode *aNode,
|
||||
nsString &aParentTag,
|
||||
nsIDOMNode *aBlockParentNode,
|
||||
nsString &aBlockParentTag,
|
||||
BlockTransformationType aTranformation,
|
||||
nsIDOMNode **aNewParentNode);
|
||||
|
||||
/* NS_IMETHOD ReParentContentOfRange(nsIDOMRange *aRange,
|
||||
nsString &aParentTag,
|
||||
BlockTransformationType aTranformation);
|
||||
*/
|
||||
NS_IMETHOD RemoveParagraphStyleFromRange(nsIDOMRange *aRange);
|
||||
|
||||
NS_IMETHOD RemoveParagraphStyleFromBlockContent(nsIDOMRange *aRange);
|
||||
|
||||
NS_IMETHOD RemoveParentFromRange(const nsString &aParentTag, nsIDOMRange *aRange);
|
||||
|
||||
NS_IMETHOD RemoveParentFromBlockContent(const nsString &aParentTag, nsIDOMRange *aRange);
|
||||
|
||||
NS_IMETHOD IsRootTag(nsString &aTag, PRBool &aIsTag);
|
||||
|
||||
NS_IMETHOD IsLeafThatTakesInlineStyle(const nsString *aTag, PRBool &aResult);
|
||||
|
||||
NS_IMETHOD IsSubordinateBlock(nsString &aTag, PRBool &aIsTag);
|
||||
|
||||
static PRBool IsTable(nsIDOMNode *aNode);
|
||||
|
@ -439,133 +424,18 @@ protected:
|
|||
const nsString *aAttributes,
|
||||
PRBool &aIsSet) const;
|
||||
|
||||
/** Moves the content between (aNode, aStartOffset) and (aNode, aEndOffset)
|
||||
* into aNewParentNode, splitting aNode as necessary to maintain the relative
|
||||
* position of all leaf content.
|
||||
* @param aNode The node whose content we're repositioning.
|
||||
* aNode can be either a text node or a container node.
|
||||
* @param aNewParentNode The node that will be the repositioned contents' parent.
|
||||
* The caller is responsible for allocating aNewParentNode
|
||||
* @param aStartOffset The start offset of the content of aNode
|
||||
* @param aEndOffset The end offset of the content of aNode.
|
||||
*/
|
||||
NS_IMETHOD MoveContentOfNodeIntoNewParent(nsIDOMNode *aNode,
|
||||
nsIDOMNode *aNewParentNode,
|
||||
PRInt32 aStartOffset,
|
||||
PRInt32 aEndOffset);
|
||||
|
||||
/** Moves the content between (aStartNode, aStartOffset) and (aEndNode, aEndOffset)
|
||||
* into aNewParentNode, splitting aStartNode and aEndNode as necessary to maintain
|
||||
* the relative position of all leaf content.
|
||||
* The content between the two endpoints MUST be "contiguous" in the sense that
|
||||
* it is all in the same block. Another way of saying this is all content nodes
|
||||
* between aStartNode and aEndNode must be inline.
|
||||
* @see IntermediateNodesAreInline
|
||||
*
|
||||
* @param aStartNode The left node, can be either a text node or a container node.
|
||||
* @param aStartOffset The start offset in the content of aStartNode
|
||||
* @param aEndNode The right node, can be either a text node or a container node.
|
||||
* @param aEndOffset The end offset in the content of aEndNode.
|
||||
* @param aGrandParentNode The common ancestor of aStartNode and aEndNode.
|
||||
* aGrandParentNode will be the parent of aNewParentNode.
|
||||
* @param aNewParentNode The node that will be the repositioned contents' parent.
|
||||
* The caller is responsible for allocating aNewParentNode
|
||||
*/
|
||||
NS_IMETHOD MoveContiguousContentIntoNewParent(nsIDOMNode *aStartNode,
|
||||
PRInt32 aStartOffset,
|
||||
nsIDOMNode *aEndNode,
|
||||
PRInt32 aEndOffset,
|
||||
nsIDOMNode *aGrandParentNode,
|
||||
nsIDOMNode *aNewParentNode);
|
||||
|
||||
|
||||
NS_IMETHOD SetTextPropertiesForNode(nsIDOMNode *aNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aStartOffset,
|
||||
PRInt32 aEndOffset,
|
||||
nsIAtom *aPropName,
|
||||
const nsString *aAttribute,
|
||||
const nsString *aValue);
|
||||
|
||||
NS_IMETHOD SetTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode,
|
||||
PRInt32 aStartOffset,
|
||||
nsIDOMNode *aEndNode,
|
||||
PRInt32 aEndOffset,
|
||||
nsIDOMNode *aParent,
|
||||
nsIAtom *aPropName,
|
||||
const nsString *aAttribute,
|
||||
const nsString *aValue);
|
||||
|
||||
NS_IMETHOD SetTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRange,
|
||||
nsIDOMNode *aStartNode,
|
||||
PRInt32 aStartOffset,
|
||||
nsIDOMNode *aEndNode,
|
||||
PRInt32 aEndOffset,
|
||||
nsIDOMNode *aParent,
|
||||
nsIAtom *aPropName,
|
||||
const nsString *aAttribute,
|
||||
const nsString *aValue);
|
||||
|
||||
NS_IMETHOD RemoveTextPropertiesForNode(nsIDOMNode *aNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aStartOffset,
|
||||
PRInt32 aEndOffset,
|
||||
nsIAtom *aPropName,
|
||||
const nsString *aAttribute);
|
||||
|
||||
NS_IMETHOD RemoveTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode,
|
||||
PRInt32 aStartOffset,
|
||||
nsIDOMNode *aEndNode,
|
||||
PRInt32 aEndOffset,
|
||||
nsIDOMNode *aParent,
|
||||
nsIAtom *aPropName,
|
||||
const nsString *aAttribute);
|
||||
|
||||
NS_IMETHOD RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStartNode,
|
||||
PRInt32 aStartOffset,
|
||||
nsIDOMNode *aEndNode,
|
||||
PRInt32 aEndOffset,
|
||||
nsIDOMNode *aParent,
|
||||
nsIAtom *aPropName,
|
||||
const nsString *aAttribute);
|
||||
|
||||
NS_IMETHOD SetTypeInStateForProperty(TypeInState &aTypeInState,
|
||||
nsIAtom *aPropName,
|
||||
const nsString *aAttribute,
|
||||
const nsString *aValue);
|
||||
|
||||
NS_IMETHOD GetTextSelectionOffsetsForRange(nsIDOMSelection *aSelection,
|
||||
nsIDOMNode **aParent,
|
||||
PRInt32 &aStartOffset,
|
||||
PRInt32 &aEndOffset);
|
||||
|
||||
void ResetTextSelectionForRange(nsIDOMNode *aParent,
|
||||
PRInt32 aStartOffset,
|
||||
PRInt32 aEndOffset,
|
||||
nsIDOMSelection *aSelection);
|
||||
|
||||
/** returns the absolute position of the end points of aSelection
|
||||
* in the document as a text stream.
|
||||
*/
|
||||
nsresult GetTextSelectionOffsets(nsIDOMSelection *aSelection,
|
||||
PRInt32 &aStartOffset,
|
||||
PRInt32 &aEndOffset);
|
||||
|
||||
nsresult GetAbsoluteOffsetsForPoints(nsIDOMNode *aInStartNode,
|
||||
PRInt32 aInStartOffset,
|
||||
nsIDOMNode *aInEndNode,
|
||||
PRInt32 aInEndOffset,
|
||||
nsIDOMNode *aInCommonParentNode,
|
||||
PRInt32 &aOutStartOffset,
|
||||
PRInt32 &aEndOffset);
|
||||
|
||||
// Methods for handling plaintext quotations
|
||||
NS_IMETHOD PasteAsPlaintextQuotation();
|
||||
NS_IMETHOD InsertAsPlaintextQuotation(const nsString& aQuotedText,
|
||||
nsIDOMNode **aNodeInserted);
|
||||
|
||||
TypeInState *GetTypeInState();
|
||||
|
||||
/** simple utility to handle any error with event listener allocation or registration */
|
||||
void HandleEventListenerError();
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "nsIEditProperty.h"
|
||||
#include "nsEditorUtils.h"
|
||||
#include "EditTxn.h"
|
||||
#include "TypeInState.h"
|
||||
|
||||
static NS_DEFINE_CID(kContentIteratorCID, NS_CONTENTITERATOR_CID);
|
||||
static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
|
||||
|
@ -227,7 +228,6 @@ nsTextEditRules::WillDoAction(nsIDOMSelection *aSelection,
|
|||
aHandled,
|
||||
info->inString,
|
||||
info->outString,
|
||||
info->typeInState,
|
||||
info->maxLength);
|
||||
case kDeleteSelection:
|
||||
return WillDeleteSelection(aSelection, info->collapsedAction, aCancel, aHandled);
|
||||
|
@ -340,7 +340,7 @@ nsTextEditRules::WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel)
|
|||
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// get prior node
|
||||
res = GetPriorHTMLNode(selNode, selOffset, &priorNode);
|
||||
res = mEditor->GetPriorHTMLNode(selNode, selOffset, &priorNode);
|
||||
if (NS_SUCCEEDED(res) && priorNode && nsHTMLEditUtils::IsMozBR(priorNode))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> block1, block2;
|
||||
|
@ -487,12 +487,12 @@ nsTextEditRules::DidInsertBreak(nsIDOMSelection *aSelection, nsresult aResult)
|
|||
nsresult res;
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = GetPriorHTMLNode(selNode, selOffset, &nearNode);
|
||||
res = mEditor->GetPriorHTMLNode(selNode, selOffset, &nearNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (nearNode && nsHTMLEditUtils::IsBreak(nearNode) && !nsHTMLEditUtils::IsMozBR(nearNode))
|
||||
{
|
||||
PRBool bIsLast;
|
||||
res = IsLastEditableChild(nearNode, &bIsLast);
|
||||
res = mEditor->IsLastEditableChild(nearNode, &bIsLast);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (bIsLast)
|
||||
{
|
||||
|
@ -514,18 +514,15 @@ nsTextEditRules::DidInsertBreak(nsIDOMSelection *aSelection, nsresult aResult)
|
|||
nsresult
|
||||
nsTextEditRules::WillInsertText(PRInt32 aAction,
|
||||
nsIDOMSelection *aSelection,
|
||||
PRBool *aCancel,
|
||||
PRBool *aCancel,
|
||||
PRBool *aHandled,
|
||||
const nsString *aInString,
|
||||
nsString *aOutString,
|
||||
TypeInState aTypeInState,
|
||||
const nsString *inString,
|
||||
nsString *outString,
|
||||
PRInt32 aMaxLength)
|
||||
{
|
||||
if (!aSelection || !aCancel || !aHandled || !aInString || !aOutString)
|
||||
{return NS_ERROR_NULL_POINTER;}
|
||||
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
|
||||
{
|
||||
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
if (aInString->IsEmpty() && (aAction != kInsertTextIME))
|
||||
if (inString->IsEmpty() && (aAction != kInsertTextIME))
|
||||
{
|
||||
// HACK: this is a fix for bug 19395
|
||||
// I can't outlaw all empty insertions
|
||||
|
@ -536,28 +533,16 @@ nsTextEditRules::WillInsertText(PRInt32 aAction,
|
|||
*aHandled = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult res;
|
||||
|
||||
// initialize out params
|
||||
|
||||
// initialize out param
|
||||
*aCancel = PR_FALSE;
|
||||
*aHandled = PR_TRUE;
|
||||
*aOutString = *aInString;
|
||||
PRInt32 start=0; PRInt32 end=0;
|
||||
nsresult res;
|
||||
nsCOMPtr<nsIDOMNode> selNode;
|
||||
PRInt32 selOffset;
|
||||
|
||||
// handle docs with a max length
|
||||
res = TruncateInsertionIfNeeded(aSelection, aInString, aOutString, aMaxLength);
|
||||
if (NS_FAILED(res)) return res;
|
||||
char specialChars[] = {'\t','\n',0};
|
||||
|
||||
// handle password field docs
|
||||
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
||||
{
|
||||
res = mEditor->GetTextSelectionOffsets(aSelection, start, end);
|
||||
NS_ASSERTION((NS_SUCCEEDED(res)), "getTextSelectionOffsets failed!");
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
|
||||
// if the selection isn't collapsed, delete it.
|
||||
PRBool bCollapsed;
|
||||
res = aSelection->GetIsCollapsed(&bCollapsed);
|
||||
|
@ -573,69 +558,132 @@ nsTextEditRules::WillInsertText(PRInt32 aAction,
|
|||
// initialize out param
|
||||
// we want to ignore result of WillInsert()
|
||||
*aCancel = PR_FALSE;
|
||||
|
||||
// get the (collapsed) selection location
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// handle password field data
|
||||
// this has the side effect of changing all the characters in aOutString
|
||||
// to the replacement character
|
||||
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
||||
{
|
||||
res = EchoInsertionToPWBuff(start, end, aOutString);
|
||||
// dont put text in places that cant have it
|
||||
nsAutoString textTag = "__moz_text";
|
||||
if (!mEditor->IsTextNode(selNode) && !mEditor->CanContainTag(selNode, textTag))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// we need to get the doc
|
||||
nsCOMPtr<nsIDOMDocument>doc;
|
||||
res = mEditor->GetDocument(getter_AddRefs(doc));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!doc) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (aAction == kInsertTextIME)
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(*inString, &selNode, &selOffset, doc);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
// if we're a single line control, pretreat the input string to remove returns
|
||||
// this is unnecessary if we use <BR>'s for breaks in "plain text", because
|
||||
// InsertBreak() checks the string. But we don't currently do that, so we need this
|
||||
// fixes bug 21032
|
||||
// *** there's some debate about whether we should replace CRLF with spaces, or
|
||||
// truncate the string at the first CRLF. Here, we replace with spaces.
|
||||
// Hack: I stripped out this test for IME inserts - it screws up double byte chars
|
||||
// that happen to end in the same values as CR or LF. Bug 27699
|
||||
if (aInString->IsEmpty() && (aAction != kInsertTextIME))
|
||||
if ((nsIHTMLEditor::eEditorSingleLineMask & mFlags) && (aAction != kInsertTextIME))
|
||||
else // aAction == kInsertText
|
||||
{
|
||||
aOutString->ReplaceChar(CRLF, ' ');
|
||||
}
|
||||
|
||||
// time to do actual text insertion ------------------------------
|
||||
|
||||
PRBool bCancel;
|
||||
char newlineChar[] = {'\n',0};
|
||||
nsString theString(*aOutString); // copy instring for now
|
||||
|
||||
// do the text insertion (IME case)
|
||||
if(aAction == kInsertTextIME)
|
||||
{
|
||||
// special case for IME. We need this to
|
||||
// handle null strings, which are meaningful for IME
|
||||
res = DoTextInsertion(aSelection, &bCancel, &theString, aTypeInState);
|
||||
return res;
|
||||
}
|
||||
|
||||
// do text insertion (non-IME case)
|
||||
while (theString.Length())
|
||||
{
|
||||
nsString partialString;
|
||||
PRInt32 pos = theString.FindCharInSet(newlineChar);
|
||||
// if first char is special, then use just it
|
||||
if (pos == 0) pos = 1;
|
||||
if (pos == -1) pos = theString.Length();
|
||||
theString.Left(partialString, pos);
|
||||
theString.Cut(0, pos);
|
||||
|
||||
// is it a solo return?
|
||||
if (partialString.Equals("\n"))
|
||||
// find where we are
|
||||
nsCOMPtr<nsIDOMNode> curNode = selNode;
|
||||
PRInt32 curOffset = selOffset;
|
||||
|
||||
// is our text going to be PREformatted?
|
||||
// We remember this so that we know how to handle tabs.
|
||||
PRBool isPRE;
|
||||
res = mEditor->IsPreformatted(selNode, &isPRE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// dont spaz my selection in subtransactions
|
||||
nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
|
||||
nsSubsumeStr subStr;
|
||||
const PRUnichar *unicodeBuf = inString->GetUnicode();
|
||||
nsCOMPtr<nsIDOMNode> unused;
|
||||
PRInt32 pos = 0;
|
||||
|
||||
// for efficiency, break out the pre case seperately. This is because
|
||||
// its a lot cheaper to search the input string for only newlines than
|
||||
// it is to search for both tabs and newlines.
|
||||
if (isPRE)
|
||||
{
|
||||
res = mEditor->InsertBreak();
|
||||
char newlineChar = '\n';
|
||||
while (unicodeBuf && (pos != -1) && (pos < inString->Length()))
|
||||
{
|
||||
PRInt32 oldPos = pos;
|
||||
PRInt32 subStrLen;
|
||||
pos = inString->FindChar(newlineChar, PR_FALSE, oldPos);
|
||||
|
||||
if (pos != -1)
|
||||
{
|
||||
subStrLen = pos - oldPos;
|
||||
// if first char is newline, then use just it
|
||||
if (subStrLen == 0)
|
||||
subStrLen = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
subStrLen = inString->Length() - oldPos;
|
||||
pos = inString->Length();
|
||||
}
|
||||
|
||||
subStr.Subsume((PRUnichar*)&unicodeBuf[oldPos], PR_FALSE, subStrLen);
|
||||
|
||||
// is it a return?
|
||||
if (subStr.Equals("\n"))
|
||||
{
|
||||
res = mEditor->JoeCreateBR(&curNode, &curOffset, &unused, nsIEditor::eNone);
|
||||
pos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(subStr, &curNode, &curOffset, doc);
|
||||
}
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
res = DoTextInsertion(aSelection, &bCancel, &partialString, aTypeInState);
|
||||
}
|
||||
if (NS_FAILED(res)) return res;
|
||||
pos = theString.FindCharInSet(newlineChar);
|
||||
}
|
||||
char specialChars[] = {'\t','\n',0};
|
||||
nsAutoString tabString = " ";
|
||||
while (unicodeBuf && (pos != -1) && (pos < inString->Length()))
|
||||
{
|
||||
PRInt32 oldPos = pos;
|
||||
PRInt32 subStrLen;
|
||||
pos = inString->FindCharInSet(specialChars, oldPos);
|
||||
|
||||
if (pos != -1)
|
||||
{
|
||||
subStrLen = pos - oldPos;
|
||||
// if first char is newline, then use just it
|
||||
if (subStrLen == 0)
|
||||
subStrLen = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
subStrLen = inString->Length() - oldPos;
|
||||
pos = inString->Length();
|
||||
}
|
||||
|
||||
subStr.Subsume((PRUnichar*)&unicodeBuf[oldPos], PR_FALSE, subStrLen);
|
||||
|
||||
// is it a tab?
|
||||
if (subStr.Equals("\t"))
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(tabString, &curNode, &curOffset, doc);
|
||||
pos++;
|
||||
}
|
||||
// is it a return?
|
||||
else if (subStr.Equals("\n"))
|
||||
{
|
||||
res = mEditor->JoeCreateBR(&curNode, &curOffset, &unused, nsIEditor::eNone);
|
||||
pos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(subStr, &curNode, &curOffset, doc);
|
||||
}
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
if (curNode) aSelection->Collapse(curNode, curOffset);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -646,375 +694,7 @@ nsTextEditRules::DidInsertText(nsIDOMSelection *aSelection,
|
|||
return DidInsert(aSelection, aResult);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInState &aTypeInState)
|
||||
{
|
||||
// private method, we know aSelection is not null, and that it is collapsed
|
||||
NS_ASSERTION(nsnull!=aSelection, "bad selection");
|
||||
|
||||
// We know at least one style is set and we're about to insert at least one character.
|
||||
// If the selection is in a text node, split the node (even if we're at the beginning or end)
|
||||
// then put the text node inside new inline style parents.
|
||||
// Otherwise, create the text node and the new inline style parents.
|
||||
nsCOMPtr<nsIDOMNode>anchor;
|
||||
PRInt32 offset;
|
||||
nsresult res = aSelection->GetAnchorNode( getter_AddRefs(anchor));
|
||||
// createNewTextNode is a flag that tells us whether we need to create a new text node or not
|
||||
PRBool createNewTextNode = PR_TRUE;
|
||||
if (NS_SUCCEEDED(res) && NS_SUCCEEDED(aSelection->GetAnchorOffset(&offset)) && anchor)
|
||||
{
|
||||
nsCOMPtr<nsIDOMCharacterData>anchorAsText;
|
||||
anchorAsText = do_QueryInterface(anchor);
|
||||
if (anchorAsText)
|
||||
{
|
||||
createNewTextNode = PR_FALSE; // we found a text node, we'll base our insertion on it
|
||||
nsCOMPtr<nsIDOMNode>newTextNode;
|
||||
// create an empty text node by splitting the selected text node according to offset
|
||||
if (0==offset)
|
||||
{
|
||||
res = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
|
||||
}
|
||||
else
|
||||
{
|
||||
PRUint32 length;
|
||||
anchorAsText->GetLength(&length);
|
||||
if (length==(PRUint32)offset)
|
||||
{
|
||||
// newTextNode will be the left node
|
||||
res = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
|
||||
// but we want the right node in this case
|
||||
newTextNode = do_QueryInterface(anchor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// splitting anchor twice sets newTextNode as an empty text node between
|
||||
// two halves of the original text node
|
||||
res = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
|
||||
if (NS_SUCCEEDED(res)) {
|
||||
res = mEditor->SplitNode(anchorAsText, 0, getter_AddRefs(newTextNode));
|
||||
}
|
||||
}
|
||||
}
|
||||
// now we have the new text node we are going to insert into.
|
||||
// create style nodes or move it up the content hierarchy as needed.
|
||||
if ((NS_SUCCEEDED(res)) && newTextNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>newStyleNode;
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_BOLD))
|
||||
{
|
||||
if (PR_TRUE==aTypeInState.GetBold()) {
|
||||
res = InsertStyleNode(newTextNode, nsIEditProperty::b, aSelection, getter_AddRefs(newStyleNode));
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>parent;
|
||||
res = newTextNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_NULL_POINTER;
|
||||
res = mEditor->RemoveTextPropertiesForNode (newTextNode, parent, 0, 0, nsIEditProperty::b, nsnull);
|
||||
}
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_ITALIC))
|
||||
{
|
||||
if (PR_TRUE==aTypeInState.GetItalic()) {
|
||||
res = InsertStyleNode(newTextNode, nsIEditProperty::i, aSelection, getter_AddRefs(newStyleNode));
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>parent;
|
||||
res = newTextNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_NULL_POINTER;
|
||||
res = mEditor->RemoveTextPropertiesForNode (newTextNode, parent, 0, 0, nsIEditProperty::i, nsnull);
|
||||
}
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_UNDERLINE))
|
||||
{
|
||||
if (PR_TRUE==aTypeInState.GetUnderline()) {
|
||||
res = InsertStyleNode(newTextNode, nsIEditProperty::u, aSelection, getter_AddRefs(newStyleNode));
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>parent;
|
||||
res = newTextNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_NULL_POINTER;
|
||||
res = mEditor->RemoveTextPropertiesForNode (newTextNode, parent, 0, 0, nsIEditProperty::u, nsnull);
|
||||
}
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTCOLOR))
|
||||
{
|
||||
nsAutoString value;
|
||||
aTypeInState.GetFontColor(value);
|
||||
nsAutoString attr;
|
||||
nsIEditProperty::color->ToString(attr);
|
||||
res = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTFACE))
|
||||
{
|
||||
nsAutoString value;
|
||||
aTypeInState.GetFontFace(value);
|
||||
nsAutoString attr;
|
||||
nsIEditProperty::face->ToString(attr);
|
||||
res = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTSIZE))
|
||||
{
|
||||
nsAutoString value;
|
||||
aTypeInState.GetFontSize(value);
|
||||
nsAutoString attr;
|
||||
nsIEditProperty::size->ToString(attr);
|
||||
res = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we have no text node, so create a new style tag(s) with a newly created text node in it
|
||||
// this is a separate case from the code above because that code needs to handle turning
|
||||
// properties on and off, this code only turns them on
|
||||
if (PR_TRUE==createNewTextNode)
|
||||
{
|
||||
offset = 0;
|
||||
nsCOMPtr<nsIDOMNode>parent = do_QueryInterface(anchor);
|
||||
if (parent)
|
||||
{ // we have a selection, get the offset within the parent
|
||||
res = aSelection->GetAnchorOffset(&offset);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement> bodyElement;
|
||||
res = mEditor->GetBodyElement(getter_AddRefs(bodyElement));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!bodyElement) return NS_ERROR_NULL_POINTER;
|
||||
parent = do_QueryInterface(bodyElement);
|
||||
// offset already set to 0
|
||||
}
|
||||
if (!parent) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
nsAutoString attr, value;
|
||||
|
||||
// now we've got the parent. insert the style tag(s)
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_BOLD))
|
||||
{
|
||||
if (PR_TRUE==aTypeInState.GetBold()) {
|
||||
res = InsertStyleAndNewTextNode(parent, offset,
|
||||
nsIEditProperty::b, attr, value,
|
||||
aSelection);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
}
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_ITALIC))
|
||||
{
|
||||
if (PR_TRUE==aTypeInState.GetItalic()) {
|
||||
res = InsertStyleAndNewTextNode(parent, offset,
|
||||
nsIEditProperty::i, attr, value,
|
||||
aSelection);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
}
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_UNDERLINE))
|
||||
{
|
||||
if (PR_TRUE==aTypeInState.GetUnderline()) {
|
||||
res = InsertStyleAndNewTextNode(parent, offset,
|
||||
nsIEditProperty::u, attr, value,
|
||||
aSelection);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
}
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTCOLOR))
|
||||
{
|
||||
aTypeInState.GetFontColor(value);
|
||||
nsIEditProperty::color->ToString(attr);
|
||||
res = InsertStyleAndNewTextNode(parent, offset,
|
||||
nsIEditProperty::font, attr, value,
|
||||
aSelection);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTFACE))
|
||||
{
|
||||
aTypeInState.GetFontFace(value);
|
||||
nsIEditProperty::face->ToString(attr);
|
||||
res = InsertStyleAndNewTextNode(parent, offset,
|
||||
nsIEditProperty::font, attr, value,
|
||||
aSelection);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTSIZE))
|
||||
{
|
||||
aTypeInState.GetFontSize(value);
|
||||
nsIEditProperty::size->ToString(attr);
|
||||
res = InsertStyleAndNewTextNode(parent, offset,
|
||||
nsIEditProperty::font, attr, value,
|
||||
aSelection);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::CreateFontStyleForInsertText(nsIDOMNode *aNewTextNode,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue,
|
||||
nsIDOMSelection *aSelection)
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
nsCOMPtr<nsIDOMNode>newStyleNode;
|
||||
if (0!=aValue.Length())
|
||||
{
|
||||
res = InsertStyleNode(aNewTextNode, nsIEditProperty::font, aSelection, getter_AddRefs(newStyleNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!newStyleNode) return NS_ERROR_NULL_POINTER;
|
||||
nsCOMPtr<nsIDOMElement>element = do_QueryInterface(newStyleNode);
|
||||
if (element) {
|
||||
res = mEditor->SetAttribute(element, aAttr, aValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>parent;
|
||||
res = aNewTextNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_NULL_POINTER;
|
||||
res = mEditor->RemoveTextPropertiesForNode (aNewTextNode, parent, 0, 0, nsIEditProperty::font, &aAttr);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::InsertStyleNode(nsIDOMNode *aNode,
|
||||
nsIAtom *aTag,
|
||||
nsIDOMSelection *aSelection,
|
||||
nsIDOMNode **aNewNode)
|
||||
{
|
||||
NS_ASSERTION(aNode && aTag, "bad args");
|
||||
if (!aNode || !aTag) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
nsresult res;
|
||||
nsCOMPtr<nsIDOMNode>parent;
|
||||
res = aNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsAutoString tag;
|
||||
aTag->ToString(tag);
|
||||
|
||||
if (PR_FALSE == mEditor->CanContainTag(parent, tag)) {
|
||||
NS_ASSERTION(PR_FALSE, "bad use of InsertStyleNode");
|
||||
return NS_ERROR_FAILURE; // illegal place to insert the style tag
|
||||
}
|
||||
|
||||
PRInt32 offsetInParent;
|
||||
res = nsEditor::GetChildOffset(aNode, parent, offsetInParent);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
res = mEditor->CreateNode(tag, parent, offsetInParent, aNewNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!aNewNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
res = mEditor->DeleteNode(aNode);
|
||||
if (NS_SUCCEEDED(res))
|
||||
{
|
||||
res = mEditor->InsertNode(aNode, *aNewNode, 0);
|
||||
if (NS_SUCCEEDED(res)) {
|
||||
if (aSelection) {
|
||||
res = aSelection->Collapse(aNode, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::InsertStyleAndNewTextNode(nsIDOMNode *aParentNode,
|
||||
PRInt32 aOffset,
|
||||
nsIAtom *aTag,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue,
|
||||
nsIDOMSelection *aInOutSelection)
|
||||
{
|
||||
NS_ASSERTION(aParentNode && aTag, "bad args");
|
||||
if (!aParentNode || !aTag) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
nsresult res;
|
||||
// if the selection already points to a text node, just call InsertStyleNode()
|
||||
if (aInOutSelection)
|
||||
{
|
||||
PRBool isCollapsed;
|
||||
aInOutSelection->GetIsCollapsed(&isCollapsed);
|
||||
if (PR_TRUE==isCollapsed)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>anchor;
|
||||
PRInt32 offset;
|
||||
res = aInOutSelection->GetAnchorNode(getter_AddRefs(anchor));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!anchor) return NS_ERROR_NULL_POINTER;
|
||||
res = aInOutSelection->GetAnchorOffset(&offset); // remember where we were
|
||||
if (NS_FAILED(res)) return res;
|
||||
// if we have a text node, just wrap it in a new style node
|
||||
if (PR_TRUE==mEditor->IsTextNode(anchor))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> newStyleNode;
|
||||
res = InsertStyleNode(anchor, aTag, aInOutSelection, getter_AddRefs(newStyleNode));
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
if (!newStyleNode) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
// if we were given an attribute, set it on the new style node
|
||||
PRInt32 attrLength = aAttr.Length();
|
||||
if (0!=attrLength)
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement>newStyleElement = do_QueryInterface(newStyleNode);
|
||||
res = mEditor->SetAttribute(newStyleElement, aAttr, aValue);
|
||||
}
|
||||
if (NS_SUCCEEDED(res)) {
|
||||
res = aInOutSelection->Collapse(anchor, offset);
|
||||
}
|
||||
return res; // we return here because we used the text node passed into us via collapsed selection
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we get here, there is no selected text node so we create one.
|
||||
// first, create the style node
|
||||
nsAutoString tag;
|
||||
aTag->ToString(tag);
|
||||
if (PR_FALSE == mEditor->CanContainTag(aParentNode, tag)) {
|
||||
NS_ASSERTION(PR_FALSE, "bad use of InsertStyleAndNewTextNode");
|
||||
return NS_ERROR_FAILURE; // illegal place to insert the style tag
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode>newStyleNode;
|
||||
nsCOMPtr<nsIDOMNode>newTextNode;
|
||||
res = mEditor->CreateNode(tag, aParentNode, aOffset, getter_AddRefs(newStyleNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!newStyleNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// if we were given an attribute, set it on the new style node
|
||||
PRInt32 attrLength = aAttr.Length();
|
||||
if (0!=attrLength)
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement>newStyleElement = do_QueryInterface(newStyleNode);
|
||||
res = mEditor->SetAttribute(newStyleElement, aAttr, aValue);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
// then create the text node
|
||||
nsAutoString textNodeTag;
|
||||
res = nsEditor::GetTextNodeTag(textNodeTag);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
|
||||
res = mEditor->CreateNode(textNodeTag, newStyleNode, 0, getter_AddRefs(newTextNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!newTextNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// if we have a selection collapse the selection to the beginning of the new text node
|
||||
if (aInOutSelection) {
|
||||
res = aInOutSelection->Collapse(newTextNode, 0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::WillSetTextProperty(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled)
|
||||
|
@ -1553,12 +1233,6 @@ nsTextEditRules::EchoInsertionToPWBuff(PRInt32 aStart, PRInt32 aEnd, nsString *a
|
|||
// manage the password buffer
|
||||
mPasswordText.Insert(*aOutString, aStart);
|
||||
|
||||
#ifdef DEBUG_jfrancis
|
||||
char *password = mPasswordText.ToNewCString();
|
||||
printf("mPasswordText is %s\n", password);
|
||||
nsCRT::free(password);
|
||||
#endif
|
||||
|
||||
// change the output to '*' only
|
||||
PRInt32 length = aOutString->Length();
|
||||
PRInt32 i;
|
||||
|
@ -1570,316 +1244,6 @@ nsTextEditRules::EchoInsertionToPWBuff(PRInt32 aStart, PRInt32 aEnd, nsString *a
|
|||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::DoTextInsertion(nsIDOMSelection *aSelection,
|
||||
PRBool *aCancel,
|
||||
const nsString *aInString,
|
||||
TypeInState aTypeInState)
|
||||
{
|
||||
if (!aSelection || !aCancel || !aInString) {return NS_ERROR_NULL_POINTER;}
|
||||
nsresult res = NS_OK;
|
||||
|
||||
// for now, we always cancel editor handling of insert text.
|
||||
// rules code always does the insertion
|
||||
*aCancel = PR_TRUE;
|
||||
|
||||
PRBool bCancel;
|
||||
res = WillInsert(aSelection, &bCancel);
|
||||
if (NS_SUCCEEDED(res) && (!bCancel))
|
||||
{
|
||||
if (PR_TRUE==aTypeInState.IsAnySet())
|
||||
{ // for every property that is set, insert a new inline style node
|
||||
res = CreateStyleForInsertText(aSelection, aTypeInState);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
}
|
||||
res = mEditor->InsertTextImpl(*aInString);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetPriorHTMLSibling: returns the previous editable sibling, if there is
|
||||
// one within the parent
|
||||
//
|
||||
nsresult
|
||||
nsTextEditRules::GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
|
||||
{
|
||||
if (!outNode || !inNode) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
*outNode = nsnull;
|
||||
nsCOMPtr<nsIDOMNode> temp, node = do_QueryInterface(inNode);
|
||||
|
||||
while (1)
|
||||
{
|
||||
res = node->GetPreviousSibling(getter_AddRefs(temp));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!temp) return NS_OK; // return null sibling
|
||||
// if it's editable, we're done
|
||||
if (mEditor->IsEditable(temp)) break;
|
||||
// otherwise try again
|
||||
node = temp;
|
||||
}
|
||||
*outNode = temp;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetPriorHTMLSibling: returns the previous editable sibling, if there is
|
||||
// one within the parent. just like above routine but
|
||||
// takes a parent/offset instead of a node.
|
||||
//
|
||||
nsresult
|
||||
nsTextEditRules::GetPriorHTMLSibling(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
|
||||
{
|
||||
if (!outNode || !inParent) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
*outNode = nsnull;
|
||||
if (!inOffset) return NS_OK; // return null sibling if at offset zero
|
||||
nsCOMPtr<nsIDOMNode> node = nsEditor::GetChildAt(inParent,inOffset-1);
|
||||
if (mEditor->IsEditable(node))
|
||||
{
|
||||
*outNode = node;
|
||||
return res;
|
||||
}
|
||||
// else
|
||||
return GetPriorHTMLSibling(node, outNode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetNextHTMLSibling: returns the next editable sibling, if there is
|
||||
// one within the parent
|
||||
//
|
||||
nsresult
|
||||
nsTextEditRules::GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
|
||||
{
|
||||
if (!outNode) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
*outNode = nsnull;
|
||||
nsCOMPtr<nsIDOMNode> temp, node = do_QueryInterface(inNode);
|
||||
|
||||
while (1)
|
||||
{
|
||||
res = node->GetNextSibling(getter_AddRefs(temp));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!temp) return NS_ERROR_FAILURE;
|
||||
// if it's editable, we're done
|
||||
if (mEditor->IsEditable(temp)) break;
|
||||
// otherwise try again
|
||||
node = temp;
|
||||
}
|
||||
*outNode = temp;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetNextHTMLSibling: returns the next editable sibling, if there is
|
||||
// one within the parent. just like above routine but
|
||||
// takes a parent/offset instead of a node.
|
||||
//
|
||||
nsresult
|
||||
nsTextEditRules::GetNextHTMLSibling(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
|
||||
{
|
||||
if (!outNode || !inParent) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
*outNode = nsnull;
|
||||
nsCOMPtr<nsIDOMNode> node = nsEditor::GetChildAt(inParent,inOffset);
|
||||
if (!node) return NS_OK; // return null sibling if no sibling
|
||||
if (mEditor->IsEditable(node))
|
||||
{
|
||||
*outNode = node;
|
||||
return res;
|
||||
}
|
||||
// else
|
||||
return GetPriorHTMLSibling(node, outNode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetPriorHTMLNode: returns the previous editable leaf node, if there is
|
||||
// one within the <body>
|
||||
//
|
||||
nsresult
|
||||
nsTextEditRules::GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
|
||||
{
|
||||
if (!outNode) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = mEditor->GetPriorNode(inNode, PR_TRUE, getter_AddRefs(*outNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// if it's not in the body, then zero it out
|
||||
if (*outNode && !nsHTMLEditUtils::InBody(*outNode))
|
||||
{
|
||||
*outNode = nsnull;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetPriorHTMLNode: same as above but takes {parent,offset} instead of node
|
||||
//
|
||||
nsresult
|
||||
nsTextEditRules::GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
|
||||
{
|
||||
if (!outNode) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = mEditor->GetPriorNode(inParent, inOffset, PR_TRUE, getter_AddRefs(*outNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// if it's not in the body, then zero it out
|
||||
if (*outNode && !nsHTMLEditUtils::InBody(*outNode))
|
||||
{
|
||||
*outNode = nsnull;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetNextHTMLNode: returns the previous editable leaf node, if there is
|
||||
// one within the <body>
|
||||
//
|
||||
nsresult
|
||||
nsTextEditRules::GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
|
||||
{
|
||||
if (!outNode) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = mEditor->GetNextNode(inNode, PR_TRUE, getter_AddRefs(*outNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// if it's not in the body, then zero it out
|
||||
if (*outNode && !nsHTMLEditUtils::InBody(*outNode))
|
||||
{
|
||||
*outNode = nsnull;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetNHTMLextNode: same as above but takes {parent,offset} instead of node
|
||||
//
|
||||
nsresult
|
||||
nsTextEditRules::GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
|
||||
{
|
||||
if (!outNode) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = mEditor->GetNextNode(inParent, inOffset, PR_TRUE, getter_AddRefs(*outNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// if it's not in the body, then zero it out
|
||||
if (*outNode && !nsHTMLEditUtils::InBody(*outNode))
|
||||
{
|
||||
*outNode = nsnull;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst)
|
||||
{
|
||||
// check parms
|
||||
if (!aOutIsFirst || !aNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// init out parms
|
||||
*aOutIsFirst = PR_FALSE;
|
||||
|
||||
// find first editable child and compare it to aNode
|
||||
nsCOMPtr<nsIDOMNode> parent, firstChild;
|
||||
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_FAILURE;
|
||||
res = GetFirstEditableChild(parent, &firstChild);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
*aOutIsFirst = (firstChild.get() == aNode);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast)
|
||||
{
|
||||
// check parms
|
||||
if (!aOutIsLast || !aNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// init out parms
|
||||
*aOutIsLast = PR_FALSE;
|
||||
|
||||
// find last editable child and compare it to aNode
|
||||
nsCOMPtr<nsIDOMNode> parent, lastChild;
|
||||
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_FAILURE;
|
||||
res = GetLastEditableChild(parent, &lastChild);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
*aOutIsLast = (lastChild.get() == aNode);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild)
|
||||
{
|
||||
// check parms
|
||||
if (!aOutFirstChild || !aNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// init out parms
|
||||
*aOutFirstChild = nsnull;
|
||||
|
||||
// find first editable child
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
nsresult res = aNode->GetFirstChild(getter_AddRefs(child));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
while (child && !mEditor->IsEditable(child))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> tmp;
|
||||
res = child->GetNextSibling(getter_AddRefs(tmp));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!tmp) return NS_ERROR_FAILURE;
|
||||
child = tmp;
|
||||
}
|
||||
|
||||
*aOutFirstChild = child;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild)
|
||||
{
|
||||
// check parms
|
||||
if (!aOutLastChild || !aNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// init out parms
|
||||
*aOutLastChild = nsnull;
|
||||
|
||||
// find last editable child
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
nsresult res = aNode->GetLastChild(getter_AddRefs(child));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
while (child && !mEditor->IsEditable(child))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> tmp;
|
||||
res = child->GetPreviousSibling(getter_AddRefs(tmp));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!tmp) return NS_ERROR_FAILURE;
|
||||
child = tmp;
|
||||
}
|
||||
|
||||
*aOutLastChild = child;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// CreateMozBR: put a BR node with moz attribute at {aNode, aOffset}
|
||||
//
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include "nsIDOMNode.h"
|
||||
|
||||
#include "nsEditRules.h"
|
||||
#include "TypeInState.h"
|
||||
|
||||
/** Object that encapsulates HTML text-specific editing rules.
|
||||
*
|
||||
|
@ -94,11 +93,9 @@ protected:
|
|||
PRBool *aHandled,
|
||||
const nsString *inString,
|
||||
nsString *outString,
|
||||
TypeInState typeInState,
|
||||
PRInt32 aMaxLength);
|
||||
nsresult DidInsertText(nsIDOMSelection *aSelection, nsresult aResult);
|
||||
nsresult GetTopEnclosingPre(nsIDOMNode *aNode, nsIDOMNode** aOutPreNode);
|
||||
nsresult CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInState &aTypeInState);
|
||||
|
||||
nsresult WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult DidInsertBreak(nsIDOMSelection *aSelection, nsresult aResult);
|
||||
|
@ -144,46 +141,6 @@ protected:
|
|||
|
||||
// helper functions
|
||||
|
||||
/** insert aNode into a new style node of type aTag.
|
||||
* aSelection is optional. If provided, aSelection is set to (aNode, 0)
|
||||
* if aNode was successfully placed in a new style node
|
||||
* @param aNewStyleNode [OUT] The newly created style node, if result is successful
|
||||
* undefined if result is a failure.
|
||||
*/
|
||||
nsresult InsertStyleNode(nsIDOMNode *aNode,
|
||||
nsIAtom *aTag,
|
||||
nsIDOMSelection *aSelection,
|
||||
nsIDOMNode **aNewStyleNode);
|
||||
|
||||
/** inserts a new <FONT> node and sets the aAttr attribute to aValue */
|
||||
nsresult CreateFontStyleForInsertText(nsIDOMNode *aNewTextNode,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue,
|
||||
nsIDOMSelection *aInOutSelection);
|
||||
|
||||
/** create a new style node of type aTag in aParentNode at aOffset,
|
||||
* and create a new text node in the new style node.
|
||||
*
|
||||
* @param aParentNode the node that will be the parent of the new style node
|
||||
* @param aOffset the positoin in aParentNode to put the new style node
|
||||
* @param aTag the type of style node to create
|
||||
* no validation of aTag is done, caller is responsible
|
||||
* for passing in a reasonable tag name
|
||||
* @param aAttr optional attribute to set on new style node
|
||||
* ignored if it is an empty string
|
||||
* @param aValue optional value for aAttr. Ignored if aAttr is an empty string
|
||||
* @param aInOutSelection optional. If provided and if it is collapsed to a text node,
|
||||
* we use the text node and wrap a style node around it.
|
||||
* If provided, aSelection is collapsed to (newTextNode, 0)
|
||||
* if newTextNode was successfully created.
|
||||
*/
|
||||
nsresult InsertStyleAndNewTextNode(nsIDOMNode *aParentNode,
|
||||
PRInt32 aOffset,
|
||||
nsIAtom *aTag,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue,
|
||||
nsIDOMSelection *aSelection);
|
||||
|
||||
/** replaces newllines with breaks, if needed. acts on doc portion in aRange */
|
||||
nsresult ReplaceNewlines(nsIDOMRange *aRange);
|
||||
|
||||
|
@ -201,26 +158,6 @@ protected:
|
|||
insertion text to '*'s */
|
||||
nsresult EchoInsertionToPWBuff(PRInt32 aStart, PRInt32 aEnd, nsString *aOutString);
|
||||
|
||||
/** do the actual text insertion */
|
||||
nsresult DoTextInsertion(nsIDOMSelection *aSelection,
|
||||
PRBool *aCancel,
|
||||
const nsString *aInString,
|
||||
TypeInState aTypeInState);
|
||||
|
||||
nsresult GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetPriorHTMLSibling(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetNextHTMLSibling(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
|
||||
nsresult IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst);
|
||||
nsresult IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast);
|
||||
nsresult GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild);
|
||||
nsresult GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild);
|
||||
|
||||
nsresult CreateMozBR(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outBRNode);
|
||||
|
||||
|
||||
|
@ -248,7 +185,6 @@ class nsTextRulesInfo : public nsRulesInfo
|
|||
inString(0),
|
||||
outString(0),
|
||||
outputFormat(0),
|
||||
typeInState(),
|
||||
maxLength(-1),
|
||||
collapsedAction(nsIEditor::eNext),
|
||||
bOrdered(PR_FALSE),
|
||||
|
@ -263,7 +199,6 @@ class nsTextRulesInfo : public nsRulesInfo
|
|||
const nsString *inString;
|
||||
nsString *outString;
|
||||
const nsString *outputFormat;
|
||||
TypeInState typeInState;
|
||||
PRInt32 maxLength;
|
||||
|
||||
// kDeleteSelection
|
||||
|
|
|
@ -1472,23 +1472,6 @@ nsEditor::SaveFile(nsFileSpec *aFileSpec, PRBool aReplaceExisting, PRBool aSaveC
|
|||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::SetProperties(nsVoidArray * aPropList)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::GetProperties(nsVoidArray *aPropList)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
*/
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::SetAttribute(nsIDOMElement *aElement, const nsString& aAttribute, const nsString& aValue)
|
||||
{
|
||||
|
@ -1538,47 +1521,6 @@ nsEditor::RemoveAttribute(nsIDOMElement *aElement, const nsString& aAttribute)
|
|||
}
|
||||
|
||||
|
||||
//
|
||||
// Insert a noneditable text node, e.g. formatting whitespace
|
||||
//
|
||||
nsresult
|
||||
nsEditor::InsertNoneditableTextNode(nsIDOMNode* parent, PRInt32 offset,
|
||||
nsString& aStr)
|
||||
{
|
||||
nsAutoString textNodeTag;
|
||||
nsresult res = GetTextNodeTag(textNodeTag);
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
|
||||
// Can't call CreateNode, because that will call us recursively.
|
||||
// So duplicate what it does:
|
||||
CreateElementTxn *txn;
|
||||
res = CreateTxnForCreateElement(textNodeTag, parent, offset, &txn);
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
|
||||
res = Do(txn);
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
|
||||
// Now get the pointer to the node we just created ...
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
res = txn->GetNewNode(getter_AddRefs(newNode));
|
||||
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
nsCOMPtr<nsIDOMCharacterData> newTextNode;
|
||||
newTextNode = do_QueryInterface(newNode);
|
||||
if (!newTextNode)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// ... and set its text.
|
||||
return newTextNode->SetData(aStr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::MarkNodeDirty(nsIDOMNode* aNode)
|
||||
{
|
||||
|
@ -2563,27 +2505,48 @@ NS_IMETHODIMP nsEditor::JoeInsertTextImpl(const nsString& aStringToInsert,
|
|||
nsCOMPtr<nsIDOMText> nodeAsText = do_QueryInterface(*aInOutNode);
|
||||
PRInt32 offset = *aInOutOffset;
|
||||
nsresult res;
|
||||
if (nodeAsText)
|
||||
if (mInIMEMode)
|
||||
{
|
||||
// we are inserting text into an existing text node.
|
||||
if (!nodeAsText)
|
||||
{
|
||||
// create a text node
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
res = aDoc->CreateTextNode("", getter_AddRefs(nodeAsText));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!nodeAsText) return NS_ERROR_NULL_POINTER;
|
||||
newNode = do_QueryInterface(nodeAsText);
|
||||
// then we insert it into the dom tree
|
||||
res = InsertNode(newNode, *aInOutNode, offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
offset = 0;
|
||||
}
|
||||
res = JoeInsertTextIntoTextNodeImpl(aStringToInsert, nodeAsText, offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
*aInOutOffset += aStringToInsert.Length();
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
// we are inserting text into a non-text node
|
||||
// first we have to create a textnode (this also populates it with the text)
|
||||
res = aDoc->CreateTextNode(aStringToInsert, getter_AddRefs(nodeAsText));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!nodeAsText) return NS_ERROR_NULL_POINTER;
|
||||
newNode = do_QueryInterface(nodeAsText);
|
||||
// then we insert it into the dom tree
|
||||
res = InsertNode(newNode, *aInOutNode, offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
*aInOutNode = newNode;
|
||||
*aInOutOffset = aStringToInsert.Length();
|
||||
if (nodeAsText)
|
||||
{
|
||||
// we are inserting text into an existing text node.
|
||||
res = JoeInsertTextIntoTextNodeImpl(aStringToInsert, nodeAsText, offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
*aInOutOffset += aStringToInsert.Length();
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
// we are inserting text into a non-text node
|
||||
// first we have to create a textnode (this also populates it with the text)
|
||||
res = aDoc->CreateTextNode(aStringToInsert, getter_AddRefs(nodeAsText));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!nodeAsText) return NS_ERROR_NULL_POINTER;
|
||||
newNode = do_QueryInterface(nodeAsText);
|
||||
// then we insert it into the dom tree
|
||||
res = InsertNode(newNode, *aInOutNode, offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
*aInOutNode = newNode;
|
||||
*aInOutOffset = aStringToInsert.Length();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -2594,7 +2557,20 @@ NS_IMETHODIMP nsEditor::JoeInsertTextIntoTextNodeImpl(const nsString& aStringToI
|
|||
PRInt32 aOffset)
|
||||
{
|
||||
EditTxn *txn;
|
||||
nsresult result = CreateTxnForInsertText(aStringToInsert, aTextNode, aOffset, (InsertTextTxn**)&txn);
|
||||
nsresult result;
|
||||
if (mInIMEMode)
|
||||
{
|
||||
if (!mIMETextNode)
|
||||
{
|
||||
mIMETextNode = aTextNode;
|
||||
mIMETextOffset = aOffset;
|
||||
}
|
||||
result = CreateTxnForIMEText(aStringToInsert, (IMETextTxn**)&txn);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = CreateTxnForInsertText(aStringToInsert, aTextNode, aOffset, (InsertTextTxn**)&txn);
|
||||
}
|
||||
if (NS_FAILED(result)) return result;
|
||||
|
||||
// let listeners know whats up
|
||||
|
@ -2632,148 +2608,6 @@ NS_IMETHODIMP nsEditor::JoeInsertTextIntoTextNodeImpl(const nsString& aStringToI
|
|||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsEditor::InsertTextImpl(const nsString& aStringToInsert)
|
||||
{
|
||||
// First delete the selection if needed
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
nsresult result = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(result)) return result;
|
||||
if (!selection) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
PRBool bIsCollapsed;
|
||||
selection->GetIsCollapsed(&bIsCollapsed);
|
||||
if (!bIsCollapsed)
|
||||
{
|
||||
result = DeleteSelectionImpl(nsIEditor::eNone);
|
||||
if (NS_FAILED(result)) return result;
|
||||
}
|
||||
|
||||
PRInt32 action = kOpInsertText;
|
||||
if (mInIMEMode) action = kOpInsertIMEText;
|
||||
nsAutoRules beginRulesSniffing(this, action, nsIEditor::eNext);
|
||||
|
||||
nsCOMPtr<nsIDOMCharacterData> nodeAsText;
|
||||
PRInt32 offset;
|
||||
result = PrepareToInsertText(&nodeAsText, &offset);
|
||||
|
||||
if (NS_SUCCEEDED(result))
|
||||
{
|
||||
EditTxn *txn;
|
||||
if (mInIMEMode)
|
||||
{
|
||||
if (!mIMETextNode)
|
||||
{
|
||||
mIMETextNode = nodeAsText;
|
||||
mIMETextOffset = offset;
|
||||
}
|
||||
result = CreateTxnForIMEText(aStringToInsert,(IMETextTxn**)&txn);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = CreateTxnForInsertText(aStringToInsert, nodeAsText, offset, (InsertTextTxn**)&txn);
|
||||
}
|
||||
if (NS_FAILED(result)) return result;
|
||||
if (!txn) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// let listeners know whats up
|
||||
PRInt32 i;
|
||||
nsIEditActionListener *listener;
|
||||
if (mActionListeners)
|
||||
{
|
||||
for (i = 0; i < mActionListeners->Count(); i++)
|
||||
{
|
||||
listener = (nsIEditActionListener *)mActionListeners->ElementAt(i);
|
||||
if (listener)
|
||||
listener->WillInsertText(nodeAsText, offset, aStringToInsert);
|
||||
}
|
||||
}
|
||||
|
||||
BeginUpdateViewBatch();
|
||||
result = Do(txn);
|
||||
// The transaction system (if any) has taken ownwership of txns.
|
||||
// aggTxn released at end of routine.
|
||||
NS_IF_RELEASE(txn);
|
||||
EndUpdateViewBatch();
|
||||
|
||||
// let listeners know what happened
|
||||
if (mActionListeners)
|
||||
{
|
||||
for (i = 0; i < mActionListeners->Count(); i++)
|
||||
{
|
||||
listener = (nsIEditActionListener *)mActionListeners->ElementAt(i);
|
||||
if (listener)
|
||||
listener->DidInsertText(nodeAsText, offset, aStringToInsert, result);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (NS_ERROR_EDITOR_NO_TEXTNODE==result)
|
||||
{
|
||||
// create the text node
|
||||
nsCOMPtr<nsIDOMNode> selectedNode;
|
||||
result = selection->GetAnchorNode(getter_AddRefs(selectedNode));
|
||||
if (NS_SUCCEEDED(result) && NS_SUCCEEDED(selection->GetAnchorOffset(&offset)) && selectedNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
nsAutoString textNodeTag;
|
||||
result = GetTextNodeTag(textNodeTag);
|
||||
if (NS_FAILED(result)) { return result; }
|
||||
result = CreateNode(textNodeTag, selectedNode, offset,
|
||||
getter_AddRefs(newNode));
|
||||
if (NS_SUCCEEDED(result) && newNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMCharacterData>newTextNode;
|
||||
newTextNode = do_QueryInterface(newNode);
|
||||
if (newTextNode)
|
||||
{
|
||||
selection->Collapse(newNode, 0);
|
||||
result = InsertTextImpl(aStringToInsert); // this really recurses, right?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsEditor::PrepareToInsertText(nsCOMPtr<nsIDOMCharacterData> *aOutTextNode, PRInt32 *aOutOffset)
|
||||
{
|
||||
if (!aOutTextNode || !aOutOffset) return NS_ERROR_NULL_POINTER;
|
||||
nsresult result = NS_OK;
|
||||
nsCOMPtr<nsIDOMCharacterData> nodeAsText;
|
||||
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
result = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(result)) return result;
|
||||
if (!selection) return NS_ERROR_NULL_POINTER;
|
||||
nsCOMPtr<nsIDOMNode> selNode;
|
||||
result = GetStartNodeAndOffset(selection, &selNode, aOutOffset);
|
||||
if (NS_FAILED(result)) return result;
|
||||
if (!selNode)
|
||||
{
|
||||
// should nsEditor really be concerned with the body node?
|
||||
// That's an html concept.
|
||||
nsCOMPtr<nsIDOMElement>bodyElement;
|
||||
result = GetBodyElement(getter_AddRefs(bodyElement));
|
||||
if (NS_FAILED(result)) return result;
|
||||
if (!bodyElement) return NS_ERROR_NULL_POINTER;
|
||||
nsCOMPtr<nsIDOMNode>bodyNode = do_QueryInterface(bodyElement);
|
||||
selection->Collapse(bodyNode,0);
|
||||
result = GetStartNodeAndOffset(selection, &selNode, aOutOffset);
|
||||
if (NS_FAILED(result)) return result;
|
||||
}
|
||||
|
||||
nodeAsText = do_QueryInterface(selNode);
|
||||
if (nodeAsText)
|
||||
{
|
||||
*aOutTextNode = nodeAsText;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = NS_ERROR_EDITOR_NO_TEXTNODE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsEditor::SelectEntireDocument(nsIDOMSelection *aSelection)
|
||||
{
|
||||
nsresult result;
|
||||
|
@ -3513,244 +3347,6 @@ nsEditor::IsNodeInline(nsIDOMNode *aNode, PRBool &aIsInline)
|
|||
return result;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEditor::GetBlockParent(nsIDOMNode *aNode, nsIDOMElement **aBlockParent)
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
if (!aBlockParent) {return NS_ERROR_NULL_POINTER;}
|
||||
*aBlockParent = nsnull;
|
||||
nsCOMPtr<nsIDOMNode>parent;
|
||||
nsCOMPtr<nsIDOMNode>temp;
|
||||
result = aNode->GetParentNode(getter_AddRefs(parent));
|
||||
while (NS_SUCCEEDED(result) && parent)
|
||||
{
|
||||
PRBool isInline;
|
||||
result = IsNodeInline(parent, isInline);
|
||||
if (PR_FALSE==isInline)
|
||||
{
|
||||
parent->QueryInterface(NS_GET_IID(nsIDOMElement), (void**)aBlockParent);
|
||||
break;
|
||||
}
|
||||
result = parent->GetParentNode(getter_AddRefs(temp));
|
||||
parent = do_QueryInterface(temp);
|
||||
}
|
||||
if (gNoisy) {
|
||||
printf("GetBlockParent for %p returning parent %p\n", aNode, *aBlockParent);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEditor::GetBlockSection(nsIDOMNode *aChild,
|
||||
nsIDOMNode **aLeftNode,
|
||||
nsIDOMNode **aRightNode)
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
if (!aChild || !aLeftNode || !aRightNode) {return NS_ERROR_NULL_POINTER;}
|
||||
*aLeftNode = aChild;
|
||||
*aRightNode = aChild;
|
||||
|
||||
nsCOMPtr<nsIDOMNode>sibling;
|
||||
result = aChild->GetPreviousSibling(getter_AddRefs(sibling));
|
||||
while ((NS_SUCCEEDED(result)) && sibling)
|
||||
{
|
||||
PRBool isInline;
|
||||
IsNodeInline(sibling, isInline);
|
||||
if (PR_FALSE==isInline)
|
||||
{
|
||||
nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
|
||||
if (!nodeAsText) {
|
||||
break;
|
||||
}
|
||||
// XXX: needs some logic to work for other leaf nodes besides text!
|
||||
}
|
||||
*aLeftNode = sibling;
|
||||
result = (*aLeftNode)->GetPreviousSibling(getter_AddRefs(sibling));
|
||||
}
|
||||
NS_ADDREF((*aLeftNode));
|
||||
// now do the right side
|
||||
result = aChild->GetNextSibling(getter_AddRefs(sibling));
|
||||
while ((NS_SUCCEEDED(result)) && sibling)
|
||||
{
|
||||
PRBool isInline;
|
||||
IsNodeInline(sibling, isInline);
|
||||
if (PR_FALSE==isInline)
|
||||
{
|
||||
nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
|
||||
if (!nodeAsText) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*aRightNode = sibling;
|
||||
result = (*aRightNode)->GetNextSibling(getter_AddRefs(sibling));
|
||||
}
|
||||
NS_ADDREF((*aRightNode));
|
||||
if (gNoisy) { printf("GetBlockSection returning %p %p\n",
|
||||
(*aLeftNode), (*aRightNode)); }
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEditor::GetBlockSectionsForRange(nsIDOMRange *aRange, nsISupportsArray *aSections)
|
||||
{
|
||||
if (!aRange || !aSections) {return NS_ERROR_NULL_POINTER;}
|
||||
|
||||
nsresult result;
|
||||
nsCOMPtr<nsIContentIterator>iter;
|
||||
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
|
||||
NS_GET_IID(nsIContentIterator), getter_AddRefs(iter));
|
||||
if ((NS_SUCCEEDED(result)) && iter)
|
||||
{
|
||||
nsCOMPtr<nsIDOMRange> lastRange;
|
||||
iter->Init(aRange);
|
||||
nsCOMPtr<nsIContent> currentContent;
|
||||
iter->CurrentNode(getter_AddRefs(currentContent));
|
||||
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>currentNode = do_QueryInterface(currentContent);
|
||||
if (currentNode)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> currentContentTag;
|
||||
currentContent->GetTag(*getter_AddRefs(currentContentTag));
|
||||
// <BR> divides block content ranges. We can achieve this by nulling out lastRange
|
||||
if (nsIEditProperty::br==currentContentTag.get())
|
||||
{
|
||||
lastRange = do_QueryInterface(nsnull);
|
||||
}
|
||||
else
|
||||
{
|
||||
PRBool isInlineOrText;
|
||||
result = IsNodeInline(currentNode, isInlineOrText);
|
||||
if (PR_FALSE==isInlineOrText)
|
||||
{
|
||||
PRUint16 nodeType;
|
||||
currentNode->GetNodeType(&nodeType);
|
||||
if (nsIDOMNode::TEXT_NODE == nodeType) {
|
||||
isInlineOrText = PR_TRUE;
|
||||
}
|
||||
}
|
||||
if (PR_TRUE==isInlineOrText)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>leftNode;
|
||||
nsCOMPtr<nsIDOMNode>rightNode;
|
||||
result = GetBlockSection(currentNode,
|
||||
getter_AddRefs(leftNode),
|
||||
getter_AddRefs(rightNode));
|
||||
if (gNoisy) {printf("currentNode %p has block content (%p,%p)\n", currentNode.get(), leftNode.get(), rightNode.get());}
|
||||
if ((NS_SUCCEEDED(result)) && leftNode && rightNode)
|
||||
{
|
||||
// add range to the list if it doesn't overlap with the previous range
|
||||
PRBool addRange=PR_TRUE;
|
||||
if (lastRange)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> lastStartNode;
|
||||
nsCOMPtr<nsIDOMElement> blockParentOfLastStartNode;
|
||||
lastRange->GetStartParent(getter_AddRefs(lastStartNode));
|
||||
result = GetBlockParent(lastStartNode, getter_AddRefs(blockParentOfLastStartNode));
|
||||
if ((NS_SUCCEEDED(result)) && blockParentOfLastStartNode)
|
||||
{
|
||||
if (gNoisy) {printf("lastStartNode %p has block parent %p\n", lastStartNode.get(), blockParentOfLastStartNode.get());}
|
||||
nsCOMPtr<nsIDOMElement> blockParentOfLeftNode;
|
||||
result = GetBlockParent(leftNode, getter_AddRefs(blockParentOfLeftNode));
|
||||
if ((NS_SUCCEEDED(result)) && blockParentOfLeftNode)
|
||||
{
|
||||
if (gNoisy) {printf("leftNode %p has block parent %p\n", leftNode.get(), blockParentOfLeftNode.get());}
|
||||
if (blockParentOfLastStartNode==blockParentOfLeftNode) {
|
||||
addRange = PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (PR_TRUE==addRange)
|
||||
{
|
||||
if (gNoisy) {printf("adding range, setting lastRange with start node %p\n", leftNode.get());}
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
result = nsComponentManager::CreateInstance(kCRangeCID, nsnull,
|
||||
NS_GET_IID(nsIDOMRange), getter_AddRefs(range));
|
||||
if ((NS_SUCCEEDED(result)) && range)
|
||||
{ // initialize the range
|
||||
range->SetStart(leftNode, 0);
|
||||
range->SetEnd(rightNode, 0);
|
||||
aSections->AppendElement(range);
|
||||
lastRange = do_QueryInterface(range);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* do not check result here, and especially do not return the result code.
|
||||
* we rely on iter->IsDone to tell us when the iteration is complete
|
||||
*/
|
||||
iter->Next();
|
||||
iter->CurrentNode(getter_AddRefs(currentContent));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEditor::IntermediateNodesAreInline(nsIDOMRange *aRange,
|
||||
nsIDOMNode *aStartNode,
|
||||
PRInt32 aStartOffset,
|
||||
nsIDOMNode *aEndNode,
|
||||
PRInt32 aEndOffset,
|
||||
PRBool &aResult)
|
||||
{
|
||||
aResult = PR_TRUE; // init out param. we assume the condition is true unless we find a node that violates it
|
||||
if (!aStartNode || !aEndNode || !aRange) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
nsCOMPtr<nsIContentIterator>iter;
|
||||
nsresult result;
|
||||
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
|
||||
NS_GET_IID(nsIContentIterator), getter_AddRefs(iter));
|
||||
//XXX: maybe CreateInstance is expensive, and I should keep around a static iter?
|
||||
// as long as this method can't be called recursively or re-entrantly!
|
||||
|
||||
if ((NS_SUCCEEDED(result)) && iter)
|
||||
{
|
||||
nsCOMPtr<nsIContent>startContent;
|
||||
startContent = do_QueryInterface(aStartNode);
|
||||
nsCOMPtr<nsIContent>endContent;
|
||||
endContent = do_QueryInterface(aEndNode);
|
||||
if (startContent && endContent)
|
||||
{
|
||||
iter->Init(aRange);
|
||||
nsCOMPtr<nsIContent> content;
|
||||
iter->CurrentNode(getter_AddRefs(content));
|
||||
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
||||
{
|
||||
if ((content.get() != startContent.get()) &&
|
||||
(content.get() != endContent.get()))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>currentNode;
|
||||
currentNode = do_QueryInterface(content);
|
||||
PRBool isInline=PR_FALSE;
|
||||
IsNodeInline(currentNode, isInline);
|
||||
if (PR_FALSE==isInline)
|
||||
{
|
||||
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
||||
nodeAsText = do_QueryInterface(currentNode);
|
||||
if (!nodeAsText) // text nodes don't count in this check, so ignore them
|
||||
{
|
||||
aResult = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* do not check result here, and especially do not return the result code.
|
||||
* we rely on iter->IsDone to tell us when the iteration is complete
|
||||
*/
|
||||
iter->Next();
|
||||
iter->CurrentNode(getter_AddRefs(content));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsEditor::GetPriorNode(nsIDOMNode *aParentNode,
|
||||
|
@ -4520,6 +4116,164 @@ nsEditor::HasSameBlockNodeParent(nsIDOMNode *aNode1, nsIDOMNode *aNode2)
|
|||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetBlockSection: return leftmost/rightmost nodes in aChild's block
|
||||
//
|
||||
nsresult
|
||||
nsEditor::GetBlockSection(nsIDOMNode *aChild,
|
||||
nsIDOMNode **aLeftNode,
|
||||
nsIDOMNode **aRightNode)
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
if (!aChild || !aLeftNode || !aRightNode) {return NS_ERROR_NULL_POINTER;}
|
||||
*aLeftNode = aChild;
|
||||
*aRightNode = aChild;
|
||||
|
||||
nsCOMPtr<nsIDOMNode>sibling;
|
||||
result = aChild->GetPreviousSibling(getter_AddRefs(sibling));
|
||||
while ((NS_SUCCEEDED(result)) && sibling)
|
||||
{
|
||||
PRBool isInline;
|
||||
IsNodeInline(sibling, isInline);
|
||||
if (PR_FALSE==isInline)
|
||||
{
|
||||
nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
|
||||
if (!nodeAsText) {
|
||||
break;
|
||||
}
|
||||
// XXX: needs some logic to work for other leaf nodes besides text!
|
||||
}
|
||||
*aLeftNode = sibling;
|
||||
result = (*aLeftNode)->GetPreviousSibling(getter_AddRefs(sibling));
|
||||
}
|
||||
NS_ADDREF((*aLeftNode));
|
||||
// now do the right side
|
||||
result = aChild->GetNextSibling(getter_AddRefs(sibling));
|
||||
while ((NS_SUCCEEDED(result)) && sibling)
|
||||
{
|
||||
PRBool isInline;
|
||||
IsNodeInline(sibling, isInline);
|
||||
if (PR_FALSE==isInline)
|
||||
{
|
||||
nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
|
||||
if (!nodeAsText) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*aRightNode = sibling;
|
||||
result = (*aRightNode)->GetNextSibling(getter_AddRefs(sibling));
|
||||
}
|
||||
NS_ADDREF((*aRightNode));
|
||||
if (gNoisy) { printf("GetBlockSection returning %p %p\n",
|
||||
(*aLeftNode), (*aRightNode)); }
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetBlockSectionsForRange: return list of block sections that intersect
|
||||
// this range
|
||||
nsresult
|
||||
nsEditor::GetBlockSectionsForRange(nsIDOMRange *aRange, nsISupportsArray *aSections)
|
||||
{
|
||||
if (!aRange || !aSections) {return NS_ERROR_NULL_POINTER;}
|
||||
|
||||
nsresult result;
|
||||
nsCOMPtr<nsIContentIterator>iter;
|
||||
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
|
||||
NS_GET_IID(nsIContentIterator), getter_AddRefs(iter));
|
||||
if ((NS_SUCCEEDED(result)) && iter)
|
||||
{
|
||||
nsCOMPtr<nsIDOMRange> lastRange;
|
||||
iter->Init(aRange);
|
||||
nsCOMPtr<nsIContent> currentContent;
|
||||
iter->CurrentNode(getter_AddRefs(currentContent));
|
||||
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>currentNode = do_QueryInterface(currentContent);
|
||||
if (currentNode)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> currentContentTag;
|
||||
currentContent->GetTag(*getter_AddRefs(currentContentTag));
|
||||
// <BR> divides block content ranges. We can achieve this by nulling out lastRange
|
||||
if (nsIEditProperty::br==currentContentTag.get())
|
||||
{
|
||||
lastRange = do_QueryInterface(nsnull);
|
||||
}
|
||||
else
|
||||
{
|
||||
PRBool isInlineOrText;
|
||||
result = IsNodeInline(currentNode, isInlineOrText);
|
||||
if (PR_FALSE==isInlineOrText)
|
||||
{
|
||||
PRUint16 nodeType;
|
||||
currentNode->GetNodeType(&nodeType);
|
||||
if (nsIDOMNode::TEXT_NODE == nodeType) {
|
||||
isInlineOrText = PR_TRUE;
|
||||
}
|
||||
}
|
||||
if (PR_TRUE==isInlineOrText)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>leftNode;
|
||||
nsCOMPtr<nsIDOMNode>rightNode;
|
||||
result = GetBlockSection(currentNode,
|
||||
getter_AddRefs(leftNode),
|
||||
getter_AddRefs(rightNode));
|
||||
if (gNoisy) {printf("currentNode %p has block content (%p,%p)\n", currentNode.get(), leftNode.get(), rightNode.get());}
|
||||
if ((NS_SUCCEEDED(result)) && leftNode && rightNode)
|
||||
{
|
||||
// add range to the list if it doesn't overlap with the previous range
|
||||
PRBool addRange=PR_TRUE;
|
||||
if (lastRange)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> lastStartNode;
|
||||
nsCOMPtr<nsIDOMElement> blockParentOfLastStartNode;
|
||||
lastRange->GetStartParent(getter_AddRefs(lastStartNode));
|
||||
blockParentOfLastStartNode = do_QueryInterface(GetBlockNodeParent(lastStartNode));
|
||||
if (blockParentOfLastStartNode)
|
||||
{
|
||||
if (gNoisy) {printf("lastStartNode %p has block parent %p\n", lastStartNode.get(), blockParentOfLastStartNode.get());}
|
||||
nsCOMPtr<nsIDOMElement> blockParentOfLeftNode;
|
||||
blockParentOfLeftNode = do_QueryInterface(GetBlockNodeParent(leftNode));
|
||||
if (blockParentOfLeftNode)
|
||||
{
|
||||
if (gNoisy) {printf("leftNode %p has block parent %p\n", leftNode.get(), blockParentOfLeftNode.get());}
|
||||
if (blockParentOfLastStartNode==blockParentOfLeftNode) {
|
||||
addRange = PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (PR_TRUE==addRange)
|
||||
{
|
||||
if (gNoisy) {printf("adding range, setting lastRange with start node %p\n", leftNode.get());}
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
result = nsComponentManager::CreateInstance(kCRangeCID, nsnull,
|
||||
NS_GET_IID(nsIDOMRange), getter_AddRefs(range));
|
||||
if ((NS_SUCCEEDED(result)) && range)
|
||||
{ // initialize the range
|
||||
range->SetStart(leftNode, 0);
|
||||
range->SetEnd(rightNode, 0);
|
||||
aSections->AppendElement(range);
|
||||
lastRange = do_QueryInterface(range);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* do not check result here, and especially do not return the result code.
|
||||
* we rely on iter->IsDone to tell us when the iteration is complete
|
||||
*/
|
||||
iter->Next();
|
||||
iter->CurrentNode(getter_AddRefs(currentContent));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// IsTextOrElementNode: true if node of dom type element or text
|
||||
//
|
||||
|
|
|
@ -263,10 +263,6 @@ public:
|
|||
|
||||
NS_IMETHOD DeleteNode(nsIDOMNode * aChild);
|
||||
|
||||
/* formatting within the dom tree */
|
||||
NS_IMETHOD InsertNoneditableTextNode(nsIDOMNode* aParent,
|
||||
PRInt32 aOffset,
|
||||
nsString& aStr);
|
||||
NS_IMETHOD MarkNodeDirty(nsIDOMNode* aNode);
|
||||
|
||||
|
||||
|
@ -303,7 +299,6 @@ public:
|
|||
public:
|
||||
|
||||
|
||||
NS_IMETHOD InsertTextImpl(const nsString& aStringToInsert);
|
||||
NS_IMETHOD JoeInsertTextImpl(const nsString& aStringToInsert,
|
||||
nsCOMPtr<nsIDOMNode> *aInOutNode,
|
||||
PRInt32 *aInOutOffset,
|
||||
|
@ -399,8 +394,6 @@ protected:
|
|||
*/
|
||||
NS_IMETHOD CreateTxnForRemoveStyleSheet(nsICSSStyleSheet* aSheet, RemoveStyleSheetTxn* *aTxn);
|
||||
|
||||
NS_IMETHOD PrepareToInsertText(nsCOMPtr<nsIDOMCharacterData> *aOutTextNode, PRInt32 *aOutOffset);
|
||||
|
||||
NS_IMETHOD DeleteText(nsIDOMCharacterData *aElement,
|
||||
PRUint32 aOffset,
|
||||
PRUint32 aLength);
|
||||
|
@ -529,58 +522,6 @@ public:
|
|||
/** This version is for exposure to JavaScript */
|
||||
NS_IMETHOD NodeIsBlock(nsIDOMNode *aNode, PRBool &aIsBlock);
|
||||
|
||||
/** returns the closest block parent of aNode, not including aNode itself.
|
||||
* can return null, for example if aNode is in a document fragment.
|
||||
* @param aNode The node whose parent we seek.
|
||||
* @param aBlockParent [OUT] The block parent, if any.
|
||||
* @return a success value unless an unexpected error occurs.
|
||||
*/
|
||||
static nsresult GetBlockParent(nsIDOMNode *aNode,
|
||||
nsIDOMElement **aBlockParent);
|
||||
|
||||
/** Determines the bounding nodes for the block section containing aNode.
|
||||
* The calculation is based on some nodes intrinsically being block elements
|
||||
* acording to HTML. Style sheets are not considered in this calculation.
|
||||
* <BR> tags separate block content sections. So the HTML markup:
|
||||
* <PRE>
|
||||
* <P>text1<BR>text2<B>text3</B></P>
|
||||
* </PRE>
|
||||
* contains two block content sections. The first has the text node "text1"
|
||||
* for both endpoints. The second has "text2" as the left endpoint and
|
||||
* "text3" as the right endpoint.
|
||||
* Notice that offsets aren't required, only leaf nodes. Offsets are implicit.
|
||||
*
|
||||
* @param aNode the block content returned includes aNode
|
||||
* @param aLeftNode [OUT] the left endpoint of the block content containing aNode
|
||||
* @param aRightNode [OUT] the right endpoint of the block content containing aNode
|
||||
*
|
||||
*/
|
||||
static nsresult GetBlockSection(nsIDOMNode *aNode,
|
||||
nsIDOMNode **aLeftNode,
|
||||
nsIDOMNode **aRightNode);
|
||||
|
||||
/** Compute the set of block sections in a given range.
|
||||
* A block section is the set of (leftNode, rightNode) pairs given
|
||||
* by GetBlockSection. The set is computed by computing the
|
||||
* block section for every leaf node in the range and throwing
|
||||
* out duplicates.
|
||||
*
|
||||
* @param aRange The range to compute block sections for.
|
||||
* @param aSections Allocated storage for the resulting set, stored as nsIDOMRanges.
|
||||
*/
|
||||
static nsresult GetBlockSectionsForRange(nsIDOMRange *aRange,
|
||||
nsISupportsArray *aSections);
|
||||
|
||||
/** returns PR_TRUE in out-param aResult if all nodes between (aStartNode, aStartOffset)
|
||||
* and (aEndNode, aEndOffset) are inline as defined by HTML DTD.
|
||||
*/
|
||||
static nsresult IntermediateNodesAreInline(nsIDOMRange *aRange,
|
||||
nsIDOMNode *aStartNode,
|
||||
PRInt32 aStartOffset,
|
||||
nsIDOMNode *aEndNode,
|
||||
PRInt32 aEndOffset,
|
||||
PRBool &aResult);
|
||||
|
||||
/** returns the number of things inside aNode in the out-param aCount.
|
||||
* @param aNode is the node to get the length of.
|
||||
* If aNode is text, returns number of characters.
|
||||
|
@ -690,6 +631,39 @@ public:
|
|||
static PRBool IsInlineNode(nsIDOMNode *aNode);
|
||||
static nsCOMPtr<nsIDOMNode> GetBlockNodeParent(nsIDOMNode *aNode);
|
||||
static PRBool HasSameBlockNodeParent(nsIDOMNode *aNode1, nsIDOMNode *aNode2);
|
||||
/** Determines the bounding nodes for the block section containing aNode.
|
||||
* The calculation is based on some nodes intrinsically being block elements
|
||||
* acording to HTML. Style sheets are not considered in this calculation.
|
||||
* <BR> tags separate block content sections. So the HTML markup:
|
||||
* <PRE>
|
||||
* <P>text1<BR>text2<B>text3</B></P>
|
||||
* </PRE>
|
||||
* contains two block content sections. The first has the text node "text1"
|
||||
* for both endpoints. The second has "text2" as the left endpoint and
|
||||
* "text3" as the right endpoint.
|
||||
* Notice that offsets aren't required, only leaf nodes. Offsets are implicit.
|
||||
*
|
||||
* @param aNode the block content returned includes aNode
|
||||
* @param aLeftNode [OUT] the left endpoint of the block content containing aNode
|
||||
* @param aRightNode [OUT] the right endpoint of the block content containing aNode
|
||||
*
|
||||
*/
|
||||
static nsresult GetBlockSection(nsIDOMNode *aNode,
|
||||
nsIDOMNode **aLeftNode,
|
||||
nsIDOMNode **aRightNode);
|
||||
|
||||
/** Compute the set of block sections in a given range.
|
||||
* A block section is the set of (leftNode, rightNode) pairs given
|
||||
* by GetBlockSection. The set is computed by computing the
|
||||
* block section for every leaf node in the range and throwing
|
||||
* out duplicates.
|
||||
*
|
||||
* @param aRange The range to compute block sections for.
|
||||
* @param aSections Allocated storage for the resulting set, stored as nsIDOMRanges.
|
||||
*/
|
||||
static nsresult GetBlockSectionsForRange(nsIDOMRange *aRange,
|
||||
nsISupportsArray *aSections);
|
||||
|
||||
|
||||
static PRBool IsTextOrElementNode(nsIDOMNode *aNode);
|
||||
static PRBool IsTextNode(nsIDOMNode *aNode);
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
|
||||
#include "TypeInState.h"
|
||||
|
||||
/********************************************************************
|
||||
* XPCOM cruft
|
||||
*******************************************************************/
|
||||
|
||||
NS_IMPL_ADDREF(TypeInState)
|
||||
NS_IMPL_RELEASE(TypeInState)
|
||||
|
@ -47,12 +50,282 @@ TypeInState::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* public methods
|
||||
*******************************************************************/
|
||||
|
||||
TypeInState::TypeInState() :
|
||||
mSetArray()
|
||||
,mClearedArray()
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
Reset();
|
||||
}
|
||||
|
||||
TypeInState::~TypeInState()
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
NS_IMETHODIMP TypeInState::NotifySelectionChanged()
|
||||
{
|
||||
Reset();
|
||||
return NS_OK;
|
||||
};
|
||||
}
|
||||
|
||||
void TypeInState::Reset()
|
||||
{
|
||||
PRInt32 count;
|
||||
PropItem *propItemPtr;
|
||||
|
||||
while ((count = mClearedArray.Count()))
|
||||
{
|
||||
// go backwards to keep nsVoidArray from memmoving everything each time
|
||||
count--; // nsVoidArray is zero based
|
||||
propItemPtr = (PropItem*)mClearedArray.ElementAt(count);
|
||||
mClearedArray.RemoveElementAt(count);
|
||||
if (propItemPtr) delete propItemPtr;
|
||||
}
|
||||
while ((count = mSetArray.Count()))
|
||||
{
|
||||
// go backwards to keep nsVoidArray from memmoving everything each time
|
||||
count--; // nsVoidArray is zero based
|
||||
propItemPtr = (PropItem*)mSetArray.ElementAt(count);
|
||||
mSetArray.RemoveElementAt(count);
|
||||
if (propItemPtr) delete propItemPtr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsresult TypeInState::SetProp(nsIAtom *aProp)
|
||||
{
|
||||
return SetProp(aProp,nsAutoString(),nsAutoString());
|
||||
}
|
||||
|
||||
nsresult TypeInState::SetProp(nsIAtom *aProp, const nsString &aAttr)
|
||||
{
|
||||
return SetProp(aProp,aAttr,nsAutoString());
|
||||
}
|
||||
|
||||
nsresult TypeInState::SetProp(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue)
|
||||
{
|
||||
// if it's already set we are done
|
||||
if (IsPropSet(aProp,aAttr,aValue)) return NS_OK;
|
||||
|
||||
// make a new propitem
|
||||
PropItem *item = new PropItem(aProp,aAttr,aValue);
|
||||
if (!item) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// remove it from the list of cleared properties, if we have a match
|
||||
RemovePropFromClearedList(aProp,aAttr,aValue);
|
||||
|
||||
// add it to the list of set properties
|
||||
mSetArray.AppendElement((void*)item);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult TypeInState::ClearProp(nsIAtom *aProp)
|
||||
{
|
||||
return ClearProp(aProp,nsAutoString(),nsAutoString());
|
||||
}
|
||||
|
||||
nsresult TypeInState::ClearProp(nsIAtom *aProp, const nsString &aAttr)
|
||||
{
|
||||
return ClearProp(aProp,aAttr,nsAutoString());
|
||||
}
|
||||
|
||||
nsresult TypeInState::ClearProp(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue)
|
||||
{
|
||||
// if it's already cleared we are done
|
||||
if (IsPropCleared(aProp,aAttr,aValue)) return NS_OK;
|
||||
|
||||
// make a new propitem
|
||||
PropItem *item = new PropItem(aProp,aAttr,aValue);
|
||||
if (!item) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// remove it from the list of set properties, if we have a match
|
||||
RemovePropFromSetList(aProp,aAttr,aValue);
|
||||
|
||||
// add it to the list of cleared properties
|
||||
mClearedArray.AppendElement((void*)item);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
nsresult TypeInState::ProcessClearProperty(PropItem **outPropItem)
|
||||
{
|
||||
if (!outPropItem) return NS_ERROR_NULL_POINTER;
|
||||
*outPropItem = nsnull;
|
||||
PRInt32 count = mClearedArray.Count();
|
||||
if (count) // go backwards to keep nsVoidArray from memmoving everything each time
|
||||
{
|
||||
count--; // nsVoidArray is zero based
|
||||
*outPropItem = (PropItem*)mClearedArray[count];
|
||||
mClearedArray.RemoveElementAt(count);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult TypeInState::ProcessSetProperty(PropItem **outPropItem)
|
||||
{
|
||||
if (!outPropItem) return NS_ERROR_NULL_POINTER;
|
||||
*outPropItem = nsnull;
|
||||
PRInt32 count = mSetArray.Count();
|
||||
if (count) // go backwards to keep nsVoidArray from memmoving everything each time
|
||||
{
|
||||
count--; // nsVoidArray is zero based
|
||||
*outPropItem = (PropItem*)mSetArray[count];
|
||||
mSetArray.RemoveElementAt(count);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult TypeInState::GetTypingState(PRBool &isSet, PRBool &theSetting, nsIAtom *aProp)
|
||||
{
|
||||
return GetTypingState(isSet, theSetting, aProp, nsAutoString(), nsAutoString());
|
||||
}
|
||||
|
||||
nsresult TypeInState::GetTypingState(PRBool &isSet,
|
||||
PRBool &theSetting,
|
||||
nsIAtom *aProp,
|
||||
const nsString &aAttr)
|
||||
{
|
||||
return GetTypingState(isSet, theSetting, aProp, aAttr, nsAutoString());
|
||||
}
|
||||
|
||||
|
||||
nsresult TypeInState::GetTypingState(PRBool &isSet,
|
||||
PRBool &theSetting,
|
||||
nsIAtom *aProp,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue)
|
||||
{
|
||||
if (IsPropSet(aProp, aAttr, aValue))
|
||||
{
|
||||
isSet = PR_TRUE;
|
||||
theSetting = PR_TRUE;
|
||||
}
|
||||
else if (IsPropCleared(aProp, aAttr, aValue))
|
||||
{
|
||||
isSet = PR_TRUE;
|
||||
theSetting = PR_FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
isSet = PR_FALSE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* protected methods
|
||||
*******************************************************************/
|
||||
|
||||
nsresult TypeInState::RemovePropFromSetList(nsIAtom *aProp,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue)
|
||||
{
|
||||
PRInt32 index;
|
||||
if (IsPropSet(aProp, aAttr, aValue, index))
|
||||
{
|
||||
PropItem *item = (PropItem*)mSetArray.ElementAt(index);
|
||||
mSetArray.RemoveElementAt(index);
|
||||
if (item) delete item;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult TypeInState::RemovePropFromClearedList(nsIAtom *aProp,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue)
|
||||
{
|
||||
PRInt32 index;
|
||||
if (IsPropCleared(aProp, aAttr, aValue, index))
|
||||
{
|
||||
PropItem *item = (PropItem*)mClearedArray.ElementAt(index);
|
||||
mClearedArray.RemoveElementAt(index);
|
||||
if (item) delete item;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
PRBool TypeInState::IsPropSet(nsIAtom *aProp,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue)
|
||||
{
|
||||
PRInt32 i;
|
||||
return IsPropSet(aProp, aAttr, aValue, i);
|
||||
}
|
||||
|
||||
|
||||
PRBool TypeInState::IsPropSet(nsIAtom *aProp,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue,
|
||||
PRInt32 &outIndex)
|
||||
{
|
||||
PRInt32 i, count = mSetArray.Count();
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
PropItem *item = (PropItem*)mSetArray[i];
|
||||
if ( (item->tag == aProp) &&
|
||||
(item->attr == aAttr) )
|
||||
{
|
||||
outIndex = i;
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
PRBool TypeInState::IsPropCleared(nsIAtom *aProp,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue)
|
||||
{
|
||||
PRInt32 i;
|
||||
return IsPropCleared(aProp, aAttr, aValue, i);
|
||||
}
|
||||
|
||||
|
||||
PRBool TypeInState::IsPropCleared(nsIAtom *aProp,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue,
|
||||
PRInt32 &outIndex)
|
||||
{
|
||||
PRInt32 i, count = mSetArray.Count();
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
PropItem *item = (PropItem*)mSetArray[i];
|
||||
if ( (item->tag == aProp) &&
|
||||
(item->attr == aAttr) )
|
||||
{
|
||||
outIndex = i;
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* PropItem: helper struct for TypeInState
|
||||
*******************************************************************/
|
||||
|
||||
PropItem::PropItem(nsIAtom *aTag, const nsString &aAttr, const nsString &aValue) :
|
||||
tag(aTag)
|
||||
,attr(aAttr)
|
||||
,value(aValue)
|
||||
{
|
||||
}
|
||||
|
||||
PropItem::~PropItem()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -26,6 +26,17 @@
|
|||
#include "nsIDOMSelectionListener.h"
|
||||
#include "nsIEditProperty.h"
|
||||
#include "nsString.h"
|
||||
#include "nsVoidArray.h"
|
||||
|
||||
struct PropItem
|
||||
{
|
||||
nsIAtom *tag;
|
||||
nsString attr;
|
||||
nsString value;
|
||||
|
||||
PropItem(nsIAtom *aTag, const nsString &aAttr, const nsString &aValue);
|
||||
~PropItem();
|
||||
};
|
||||
|
||||
class TypeInState : public nsIDOMSelectionListener
|
||||
{
|
||||
|
@ -39,260 +50,35 @@ public:
|
|||
|
||||
NS_IMETHOD NotifySelectionChanged();
|
||||
|
||||
void GetEnumForName(nsIAtom *aPropName, PRUint32 &aEnum);
|
||||
void GetPropertyIsString(PRUint32 aProp, PRUint32 &aIsString);
|
||||
|
||||
void SetProp(PRUint32 aProp, PRBool aSet);
|
||||
void GetProp(PRUint32 aProp, PRBool& aSet);
|
||||
|
||||
void SetPropValue(PRUint32 aProp, const nsString &aValue);
|
||||
void GetPropValue(PRUint32 aProp, nsString &aValue);
|
||||
|
||||
PRBool IsSet(PRUint32 aStyle);
|
||||
PRBool IsAnySet();
|
||||
void UnSet(PRUint32 aStyle);
|
||||
|
||||
void SetBold(PRBool aIsSet);
|
||||
PRBool GetBold();
|
||||
|
||||
void SetItalic(PRBool aIsSet);
|
||||
PRBool GetItalic();
|
||||
|
||||
void SetUnderline(PRBool aIsSet);
|
||||
PRBool GetUnderline();
|
||||
nsresult SetProp(nsIAtom *aProp);
|
||||
nsresult SetProp(nsIAtom *aProp, const nsString &aAttr);
|
||||
nsresult SetProp(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue);
|
||||
nsresult ClearProp(nsIAtom *aProp);
|
||||
nsresult ClearProp(nsIAtom *aProp, const nsString &aAttr);
|
||||
nsresult ClearProp(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue);
|
||||
|
||||
void SetFontFace(const nsString &aFace);
|
||||
void GetFontFace(nsString &aFace);
|
||||
|
||||
void SetFontColor(const nsString &aColor);
|
||||
void GetFontColor(nsString &aColor);
|
||||
|
||||
void SetFontSize(const nsString &aSize);
|
||||
void GetFontSize(nsString &aSize);
|
||||
nsresult ProcessClearProperty(PropItem **outPropItem);
|
||||
nsresult ProcessSetProperty(PropItem **outPropItem);
|
||||
|
||||
nsresult GetTypingState(PRBool &isSet, PRBool &theSetting, nsIAtom *aProp);
|
||||
nsresult GetTypingState(PRBool &isSet, PRBool &theSetting, nsIAtom *aProp,
|
||||
const nsString &aAttr);
|
||||
nsresult GetTypingState(PRBool &isSet, PRBool &theSetting, nsIAtom *aProp,
|
||||
const nsString &aAttr, const nsString &aValue);
|
||||
|
||||
protected:
|
||||
PRBool mBold;
|
||||
PRBool mItalic;
|
||||
PRBool mUnderline;
|
||||
nsString mFontFace;
|
||||
nsString mFontColor;
|
||||
nsString mFontSize;
|
||||
PRUint32 mIsSet;
|
||||
|
||||
nsresult RemovePropFromSetList(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue);
|
||||
nsresult RemovePropFromClearedList(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue);
|
||||
PRBool IsPropSet(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue);
|
||||
PRBool IsPropSet(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue, PRInt32 &outIndex);
|
||||
PRBool IsPropCleared(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue);
|
||||
PRBool IsPropCleared(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue, PRInt32 &outIndex);
|
||||
|
||||
nsVoidArray mSetArray;
|
||||
nsVoidArray mClearedArray;
|
||||
};
|
||||
|
||||
#define NS_TYPEINSTATE_UNKNOWN 0x00000000
|
||||
#define NS_TYPEINSTATE_BOLD 0x00000001
|
||||
#define NS_TYPEINSTATE_ITALIC 0x00000002
|
||||
#define NS_TYPEINSTATE_UNDERLINE 0x00000004
|
||||
#define NS_TYPEINSTATE_FONTFACE 0x00000008
|
||||
#define NS_TYPEINSTATE_FONTCOLOR 0x00000010
|
||||
#define NS_TYPEINSTATE_FONTSIZE 0x00000020
|
||||
|
||||
/* ----- inline method definitions ----- */
|
||||
inline
|
||||
void TypeInState::Reset()
|
||||
{
|
||||
mBold = PR_FALSE;
|
||||
mItalic = PR_FALSE;
|
||||
mUnderline = PR_FALSE;
|
||||
mIsSet = 0;
|
||||
};
|
||||
|
||||
inline
|
||||
TypeInState::TypeInState()
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
Reset();
|
||||
};
|
||||
|
||||
inline
|
||||
void TypeInState::GetEnumForName(nsIAtom *aPropName, PRUint32 &aEnum)
|
||||
{
|
||||
aEnum = NS_TYPEINSTATE_UNKNOWN;
|
||||
if (nsIEditProperty::b==aPropName) { aEnum = NS_TYPEINSTATE_BOLD; }
|
||||
else if (nsIEditProperty::i==aPropName) { aEnum = NS_TYPEINSTATE_ITALIC; }
|
||||
else if (nsIEditProperty::u==aPropName) { aEnum = NS_TYPEINSTATE_UNDERLINE; }
|
||||
else if (nsIEditProperty::face==aPropName) { aEnum = NS_TYPEINSTATE_FONTFACE; }
|
||||
else if (nsIEditProperty::color==aPropName) { aEnum = NS_TYPEINSTATE_FONTCOLOR; }
|
||||
else if (nsIEditProperty::size==aPropName) { aEnum = NS_TYPEINSTATE_FONTSIZE; }
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
void TypeInState::GetPropertyIsString(PRUint32 aProp, PRUint32 &aIsString)
|
||||
{
|
||||
switch (aProp)
|
||||
{
|
||||
case NS_TYPEINSTATE_BOLD:
|
||||
case NS_TYPEINSTATE_ITALIC:
|
||||
case NS_TYPEINSTATE_UNDERLINE:
|
||||
aIsString = PR_FALSE;
|
||||
break;
|
||||
|
||||
case NS_TYPEINSTATE_FONTFACE:
|
||||
case NS_TYPEINSTATE_FONTCOLOR:
|
||||
case NS_TYPEINSTATE_FONTSIZE:
|
||||
aIsString = PR_TRUE;
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("Unknown property");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
PRBool TypeInState::IsSet(PRUint32 aStyle)
|
||||
{
|
||||
if ((PRBool)(mIsSet & aStyle))
|
||||
return PR_TRUE;
|
||||
else
|
||||
return PR_FALSE;
|
||||
};
|
||||
|
||||
inline
|
||||
void TypeInState::UnSet(PRUint32 aStyle)
|
||||
{
|
||||
mIsSet &= ~aStyle;
|
||||
};
|
||||
|
||||
inline
|
||||
PRBool TypeInState::IsAnySet()
|
||||
{
|
||||
return (PRBool)(0!=mIsSet);
|
||||
}
|
||||
|
||||
inline
|
||||
void TypeInState::SetBold(PRBool aIsSet)
|
||||
{
|
||||
mBold = aIsSet;
|
||||
mIsSet |= NS_TYPEINSTATE_BOLD;
|
||||
};
|
||||
|
||||
inline
|
||||
PRBool TypeInState::GetBold()
|
||||
{ return mBold;};
|
||||
|
||||
inline
|
||||
void TypeInState::SetItalic(PRBool aIsSet)
|
||||
{
|
||||
mItalic = aIsSet;
|
||||
mIsSet |= NS_TYPEINSTATE_ITALIC;
|
||||
};
|
||||
|
||||
inline
|
||||
PRBool TypeInState::GetItalic()
|
||||
{ return mItalic; };
|
||||
|
||||
inline
|
||||
void TypeInState::SetUnderline(PRBool aIsSet)
|
||||
{
|
||||
mUnderline = aIsSet;
|
||||
mIsSet |= NS_TYPEINSTATE_UNDERLINE;
|
||||
};
|
||||
|
||||
inline
|
||||
PRBool TypeInState::GetUnderline()
|
||||
{ return mUnderline; };
|
||||
|
||||
inline
|
||||
void TypeInState::SetFontFace(const nsString &aFace)
|
||||
{
|
||||
mFontFace = aFace;
|
||||
mIsSet |= NS_TYPEINSTATE_FONTFACE;
|
||||
};
|
||||
|
||||
inline
|
||||
void TypeInState::GetFontFace(nsString &aFace)
|
||||
{ aFace = mFontFace; };
|
||||
|
||||
inline
|
||||
void TypeInState::SetFontColor(const nsString &aColor)
|
||||
{
|
||||
mFontColor = aColor;
|
||||
mIsSet |= NS_TYPEINSTATE_FONTCOLOR;
|
||||
};
|
||||
|
||||
inline
|
||||
void TypeInState::GetFontColor(nsString &aColor)
|
||||
{ aColor = mFontColor; };
|
||||
|
||||
inline
|
||||
void TypeInState::SetFontSize(const nsString &aSize)
|
||||
{
|
||||
mFontSize = aSize;
|
||||
mIsSet |= NS_TYPEINSTATE_FONTSIZE;
|
||||
};
|
||||
|
||||
inline
|
||||
void TypeInState::GetFontSize(nsString &aSize)
|
||||
{ aSize = mFontSize; };
|
||||
|
||||
inline void TypeInState::SetProp(PRUint32 aProp, PRBool aSet)
|
||||
{
|
||||
switch (aProp)
|
||||
{
|
||||
case NS_TYPEINSTATE_BOLD:
|
||||
SetBold(aSet);
|
||||
break;
|
||||
case NS_TYPEINSTATE_ITALIC:
|
||||
SetItalic(aSet);
|
||||
break;
|
||||
case NS_TYPEINSTATE_UNDERLINE:
|
||||
SetUnderline(aSet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline void TypeInState::SetPropValue(PRUint32 aProp, const nsString &aValue)
|
||||
{
|
||||
switch (aProp)
|
||||
{
|
||||
case NS_TYPEINSTATE_FONTFACE:
|
||||
SetFontFace(aValue);
|
||||
break;
|
||||
case NS_TYPEINSTATE_FONTCOLOR:
|
||||
SetFontColor(aValue);
|
||||
break;
|
||||
case NS_TYPEINSTATE_FONTSIZE:
|
||||
SetFontSize(aValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
void TypeInState::GetProp(PRUint32 aProp, PRBool& aSet)
|
||||
{
|
||||
switch (aProp)
|
||||
{
|
||||
case NS_TYPEINSTATE_BOLD:
|
||||
aSet = GetBold();
|
||||
break;
|
||||
case NS_TYPEINSTATE_ITALIC:
|
||||
aSet = GetItalic();
|
||||
break;
|
||||
case NS_TYPEINSTATE_UNDERLINE:
|
||||
aSet = GetUnderline();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
void TypeInState::GetPropValue(PRUint32 aProp, nsString &aValue)
|
||||
{
|
||||
switch (aProp)
|
||||
{
|
||||
case NS_TYPEINSTATE_FONTFACE:
|
||||
GetFontFace(aValue);
|
||||
break;
|
||||
case NS_TYPEINSTATE_FONTCOLOR:
|
||||
GetFontColor(aValue);
|
||||
break;
|
||||
case NS_TYPEINSTATE_FONTSIZE:
|
||||
GetFontSize(aValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // TypeInState_h__
|
||||
|
|
|
@ -209,6 +209,10 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
|||
res = AdjustSpecialBreaks();
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// merge any adjacent text nodes
|
||||
res = mEditor->CollapseAdjacentTextNodes(mDocChangeRange);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// adjust whitespace for insert text and delete actions
|
||||
if ((action == nsEditor::kOpInsertText) ||
|
||||
(action == nsEditor::kOpInsertIMEText) ||
|
||||
|
@ -230,8 +234,6 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
|||
res = RemoveEmptyNodes();
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
/* I'll move to this code in M15. For now being very conservative with changes
|
||||
|
||||
// adjust selection for insert text and delete actions
|
||||
if ((action == nsEditor::kOpInsertText) ||
|
||||
(action == nsEditor::kOpInsertIMEText) ||
|
||||
|
@ -240,20 +242,8 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
|||
res = AdjustSelection(selection, aDirection);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// adjust selection unless it was an inline style manipulation
|
||||
// see above commented out code: we're just being safe for now
|
||||
// with the minimal change to fix selection problem when removing
|
||||
// link property
|
||||
if ((action != nsEditor::kOpSetTextProperty) &&
|
||||
(action != nsEditor::kOpRemoveTextProperty))
|
||||
{
|
||||
res = AdjustSelection(selection, aDirection);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
|
||||
// detect empty doc
|
||||
res = CreateBogusNodeIfNeeded(selection);
|
||||
|
||||
|
@ -295,7 +285,6 @@ nsHTMLEditRules::WillDoAction(nsIDOMSelection *aSelection,
|
|||
aHandled,
|
||||
info->inString,
|
||||
info->outString,
|
||||
info->typeInState,
|
||||
info->maxLength);
|
||||
case kInsertBreak:
|
||||
return WillInsertBreak(aSelection, aCancel, aHandled);
|
||||
|
@ -342,7 +331,6 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
|
|||
PRBool *aHandled,
|
||||
const nsString *inString,
|
||||
nsString *outString,
|
||||
TypeInState typeInState,
|
||||
PRInt32 aMaxLength)
|
||||
{
|
||||
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
||||
|
@ -393,44 +381,26 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
|
|||
if (!mEditor->IsTextNode(selNode) && !mEditor->CanContainTag(selNode, textTag))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// take care of typeinstate issues
|
||||
if (typeInState.IsAnySet())
|
||||
{ // for every property that is set, insert a new inline style node
|
||||
res = CreateStyleForInsertText(aSelection, typeInState);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// refresh the (collapsed) selection location
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
// identify the block
|
||||
nsCOMPtr<nsIDOMNode> blockParent;
|
||||
|
||||
if (nsEditor::IsBlockNode(selNode))
|
||||
blockParent = selNode;
|
||||
else
|
||||
blockParent = mEditor->GetBlockNodeParent(selNode);
|
||||
if (!blockParent) return NS_ERROR_FAILURE;
|
||||
|
||||
PRBool bCancel;
|
||||
nsString theString(*inString); // copy instring for now
|
||||
if(aAction == kInsertTextIME)
|
||||
// we need to get the doc
|
||||
nsCOMPtr<nsIDOMDocument>doc;
|
||||
res = mEditor->GetDocument(getter_AddRefs(doc));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!doc) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// for every property that is set, insert a new inline style node
|
||||
res = CreateStyleForInsertText(aSelection, doc);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// refresh the (collapsed) selection location
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
if (aAction == kInsertTextIME)
|
||||
{
|
||||
// special case for IME. We need this to :
|
||||
// a) handle null strings, which are meaningful for IME
|
||||
// b) prevent the string from being broken into substrings,
|
||||
// which can happen in non-IME processing below.
|
||||
// I should probably convert runs of spaces and tabs here as well
|
||||
res = DoTextInsertion(aSelection, &bCancel, &theString, typeInState);
|
||||
res = mEditor->JoeInsertTextImpl(*inString, &selNode, &selOffset, doc);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
else // aAction == kInsertText
|
||||
{
|
||||
// we need to get the doc
|
||||
nsCOMPtr<nsIDOMDocument>doc;
|
||||
res = mEditor->GetDocument(getter_AddRefs(doc));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!doc) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// find where we are
|
||||
nsCOMPtr<nsIDOMNode> curNode = selNode;
|
||||
PRInt32 curOffset = selOffset;
|
||||
|
@ -449,9 +419,10 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
|
|||
|
||||
// dont spaz my selection in subtransactions
|
||||
nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
|
||||
nsAutoString partialString;
|
||||
nsSubsumeStr subStr;
|
||||
const PRUnichar *unicodeBuf = inString->GetUnicode();
|
||||
nsCOMPtr<nsIDOMNode> unused;
|
||||
PRInt32 pos;
|
||||
PRInt32 pos = 0;
|
||||
|
||||
// for efficiency, break out the pre case seperately. This is because
|
||||
// its a lot cheaper to search the input string for only newlines than
|
||||
|
@ -459,22 +430,36 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
|
|||
if (isPRE)
|
||||
{
|
||||
char newlineChar = '\n';
|
||||
while (theString.Length())
|
||||
while (unicodeBuf && (pos != -1) && (pos < inString->Length()))
|
||||
{
|
||||
pos = theString.FindChar(newlineChar);
|
||||
// if first char is newline, then use just it
|
||||
if (pos == 0) pos = 1;
|
||||
if (pos == -1) pos = theString.Length();
|
||||
theString.Left(partialString, pos);
|
||||
theString.Cut(0, pos);
|
||||
// is it a return?
|
||||
if (partialString.Equals("\n"))
|
||||
PRInt32 oldPos = pos;
|
||||
PRInt32 subStrLen;
|
||||
pos = inString->FindChar(newlineChar, PR_FALSE, oldPos);
|
||||
|
||||
if (pos != -1)
|
||||
{
|
||||
res = mEditor->JoeCreateBR(&curNode, &curOffset, &unused, nsIEditor::eNone);
|
||||
subStrLen = pos - oldPos;
|
||||
// if first char is newline, then use just it
|
||||
if (subStrLen == 0)
|
||||
subStrLen = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(partialString, &curNode, &curOffset, doc);
|
||||
subStrLen = inString->Length() - oldPos;
|
||||
pos = inString->Length();
|
||||
}
|
||||
|
||||
subStr.Subsume((PRUnichar*)&unicodeBuf[oldPos], PR_FALSE, subStrLen);
|
||||
|
||||
// is it a return?
|
||||
if (subStr.Equals("\n"))
|
||||
{
|
||||
res = mEditor->JoeCreateBR(&curNode, &curOffset, &unused, nsIEditor::eNone);
|
||||
pos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(subStr, &curNode, &curOffset, doc);
|
||||
}
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
@ -483,28 +468,42 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
|
|||
{
|
||||
char specialChars[] = {'\t','\n',0};
|
||||
nsAutoString tabString = " ";
|
||||
while (theString.Length())
|
||||
while (unicodeBuf && (pos != -1) && (pos < inString->Length()))
|
||||
{
|
||||
pos = theString.FindCharInSet(specialChars);
|
||||
// if first char is special, then use just it
|
||||
if (pos == 0) pos = 1;
|
||||
if (pos == -1) pos = theString.Length();
|
||||
theString.Left(partialString, pos);
|
||||
theString.Cut(0, pos);
|
||||
// is it a tab?
|
||||
if (partialString.Equals("\t"))
|
||||
PRInt32 oldPos = pos;
|
||||
PRInt32 subStrLen;
|
||||
pos = inString->FindCharInSet(specialChars, oldPos);
|
||||
|
||||
if (pos != -1)
|
||||
{
|
||||
partialString = " ";
|
||||
res = mEditor->JoeInsertTextImpl(tabString, &curNode, &curOffset, doc);
|
||||
}
|
||||
// is it a return?
|
||||
else if (partialString.Equals("\n"))
|
||||
{
|
||||
res = mEditor->JoeCreateBR(&curNode, &curOffset, &unused, nsIEditor::eNone);
|
||||
subStrLen = pos - oldPos;
|
||||
// if first char is newline, then use just it
|
||||
if (subStrLen == 0)
|
||||
subStrLen = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(partialString, &curNode, &curOffset, doc);
|
||||
subStrLen = inString->Length() - oldPos;
|
||||
pos = inString->Length();
|
||||
}
|
||||
|
||||
subStr.Subsume((PRUnichar*)&unicodeBuf[oldPos], PR_FALSE, subStrLen);
|
||||
|
||||
// is it a tab?
|
||||
if (subStr.Equals("\t"))
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(tabString, &curNode, &curOffset, doc);
|
||||
pos++;
|
||||
}
|
||||
// is it a return?
|
||||
else if (subStr.Equals("\n"))
|
||||
{
|
||||
res = mEditor->JoeCreateBR(&curNode, &curOffset, &unused, nsIEditor::eNone);
|
||||
pos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(subStr, &curNode, &curOffset, doc);
|
||||
}
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
@ -683,7 +682,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
if (!offset && (aAction == nsIEditor::ePrevious))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> priorNode;
|
||||
res = GetPriorHTMLNode(node, &priorNode);
|
||||
res = mEditor->GetPriorHTMLNode(node, &priorNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// if there is no prior node then cancel the deletion
|
||||
|
@ -705,7 +704,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
// we did something, so lets say so.
|
||||
*aHandled = PR_TRUE;
|
||||
// get new prior node
|
||||
res = GetPriorHTMLNode(node, &priorNode);
|
||||
res = mEditor->GetPriorHTMLNode(node, &priorNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// are they in same block?
|
||||
if (mEditor->HasSameBlockNodeParent(node, priorNode))
|
||||
|
@ -782,7 +781,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
&& (aAction == nsIEditor::eNext))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> nextNode;
|
||||
res = GetNextHTMLNode(node, &nextNode);
|
||||
res = mEditor->GetNextHTMLNode(node, &nextNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// if there is no next node, or it's not in the body, then cancel the deletion
|
||||
|
@ -804,7 +803,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
// we did something, so lets say so.
|
||||
*aHandled = PR_TRUE;
|
||||
// get new next node
|
||||
res = GetNextHTMLNode(node, &nextNode);
|
||||
res = mEditor->GetNextHTMLNode(node, &nextNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// are they in same block?
|
||||
if (mEditor->HasSameBlockNodeParent(node, nextNode))
|
||||
|
@ -892,9 +891,9 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
if (bIsEmptyNode && !mEditor->IsTableElement(node))
|
||||
nodeToDelete = node;
|
||||
else if (aAction == nsIEditor::ePrevious)
|
||||
res = GetPriorHTMLNode(node, offset, &nodeToDelete);
|
||||
res = mEditor->GetPriorHTMLNode(node, offset, &nodeToDelete);
|
||||
else if (aAction == nsIEditor::eNext)
|
||||
res = GetNextHTMLNode(node, offset, &nodeToDelete);
|
||||
res = mEditor->GetNextHTMLNode(node, offset, &nodeToDelete);
|
||||
else
|
||||
return NS_OK;
|
||||
|
||||
|
@ -925,7 +924,7 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
if (nsHTMLEditUtils::IsMozBR(nodeToDelete))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
res = GetPriorHTMLNode(nodeToDelete, &brNode);
|
||||
res = mEditor->GetPriorHTMLNode(nodeToDelete, &brNode);
|
||||
if (nsHTMLEditUtils::IsBreak(brNode))
|
||||
{
|
||||
// is brNode also a descendant of same block?
|
||||
|
@ -1695,6 +1694,69 @@ nsHTMLEditRules::WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel, PRBoo
|
|||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// CreateStyleForInsertText: take care of clearing and setting appropriate
|
||||
// style nodes for text insertion.
|
||||
//
|
||||
//
|
||||
nsresult
|
||||
nsHTMLEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, nsIDOMDocument *aDoc)
|
||||
{
|
||||
if (!aSelection || !aDoc) return NS_ERROR_NULL_POINTER;
|
||||
if (!mEditor->mTypeInState) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> node;
|
||||
PRInt32 offset;
|
||||
nsresult res = mEditor->GetStartNodeAndOffset(aSelection, &node, &offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
PropItem *item = nsnull;
|
||||
|
||||
// process clearing any styles first
|
||||
mEditor->mTypeInState->ProcessClearProperty(&item);
|
||||
while (item)
|
||||
{
|
||||
res = mEditor->SplitStyleAbovePoint(&node, &offset, item->tag, &item->attr);
|
||||
if (NS_FAILED(res)) return res;
|
||||
mEditor->mTypeInState->ProcessClearProperty(&item);
|
||||
}
|
||||
|
||||
// then process setting any styles
|
||||
mEditor->mTypeInState->ProcessSetProperty(&item);
|
||||
|
||||
if (item) // we have at least one style to add; make a
|
||||
{ // new text node to insert style nodes above.
|
||||
if (mEditor->IsTextNode(node))
|
||||
{
|
||||
// if we are in a text node, split it
|
||||
res = mEditor->SplitNodeDeep(node, node, offset, &offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
nsCOMPtr<nsIDOMNode> tmp;
|
||||
node->GetParentNode(getter_AddRefs(tmp));
|
||||
node = tmp;
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
nsCOMPtr<nsIDOMText> nodeAsText;
|
||||
res = aDoc->CreateTextNode("", getter_AddRefs(nodeAsText));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!nodeAsText) return NS_ERROR_NULL_POINTER;
|
||||
newNode = do_QueryInterface(nodeAsText);
|
||||
res = mEditor->InsertNode(newNode, node, offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
node = newNode;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
while (item)
|
||||
{
|
||||
res = mEditor->SetInlinePropertyOnNode(node, item->tag, &item->attr, &item->value);
|
||||
if (NS_FAILED(res)) return res;
|
||||
mEditor->mTypeInState->ProcessSetProperty(&item);
|
||||
}
|
||||
|
||||
return aSelection->Collapse(node, offset);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// IsEmptyBlock: figure out if aNode is (or is inside) an empty block.
|
||||
// A block can have children and still be considered empty,
|
||||
|
@ -2023,9 +2085,9 @@ nsHTMLEditRules::AlignTableCellContents(nsIDOMNode *aNode, const nsString *align
|
|||
nsresult res;
|
||||
nsCOMPtr <nsIDOMNode> firstChild, lastChild, divNode;
|
||||
|
||||
res = GetFirstEditableChild(aNode, &firstChild);
|
||||
res = mEditor->GetFirstEditableChild(aNode, &firstChild);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = GetLastEditableChild(aNode, &lastChild);
|
||||
res = mEditor->GetLastEditableChild(aNode, &lastChild);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!firstChild)
|
||||
{
|
||||
|
@ -2056,7 +2118,7 @@ nsHTMLEditRules::AlignTableCellContents(nsIDOMNode *aNode, const nsString *align
|
|||
{
|
||||
res = mEditor->MoveNode(lastChild, divNode, 0);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = GetLastEditableChild(aNode, &lastChild);
|
||||
res = mEditor->GetLastEditableChild(aNode, &lastChild);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
|
@ -2100,13 +2162,13 @@ nsHTMLEditRules::GetTableContent(nsIDOMNode *aNode, nsCOMPtr<nsISupportsArray> *
|
|||
if (mEditor->IsTableCell(node))
|
||||
{
|
||||
nsCOMPtr <nsIDOMNode> child, tmp;
|
||||
res = GetFirstEditableChild(node, &child);
|
||||
res = mEditor->GetFirstEditableChild(node, &child);
|
||||
if (NS_FAILED(res)) return res;
|
||||
while (child)
|
||||
{
|
||||
isupports = do_QueryInterface(child);
|
||||
(*outArrayOfNodes)->AppendElement(isupports);
|
||||
GetNextHTMLSibling(child, &tmp);
|
||||
mEditor->GetNextHTMLSibling(child, &tmp);
|
||||
child = tmp;
|
||||
}
|
||||
}
|
||||
|
@ -2208,7 +2270,7 @@ nsHTMLEditRules::AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *
|
|||
if (nodeAsText && aOffset) return PR_FALSE; // there are chars in front of us
|
||||
|
||||
nsCOMPtr<nsIDOMNode> priorNode;
|
||||
nsresult res = GetPriorHTMLNode(aNode, aOffset, &priorNode);
|
||||
nsresult res = mEditor->GetPriorHTMLNode(aNode, aOffset, &priorNode);
|
||||
if (NS_FAILED(res)) return PR_TRUE;
|
||||
if (!priorNode) return PR_TRUE;
|
||||
nsCOMPtr<nsIDOMNode> blockParent = mEditor->GetBlockNodeParent(priorNode);
|
||||
|
@ -2231,7 +2293,7 @@ nsHTMLEditRules::AtEndOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aB
|
|||
if ((PRInt32)strLength > aOffset) return PR_FALSE; // there are chars in after us
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> nextNode;
|
||||
nsresult res = GetNextHTMLNode(aNode, aOffset, &nextNode);
|
||||
nsresult res = mEditor->GetNextHTMLNode(aNode, aOffset, &nextNode);
|
||||
if (NS_FAILED(res)) return PR_TRUE;
|
||||
if (!nextNode) return PR_TRUE;
|
||||
nsCOMPtr<nsIDOMNode> blockParent = mEditor->GetBlockNodeParent(nextNode);
|
||||
|
@ -2724,7 +2786,7 @@ nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection,
|
|||
|
||||
// if the leftand heading is empty, put a mozbr in it
|
||||
nsCOMPtr<nsIDOMNode> prevItem;
|
||||
GetPriorHTMLSibling(aHeader, &prevItem);
|
||||
mEditor->GetPriorHTMLSibling(aHeader, &prevItem);
|
||||
if (prevItem && nsHTMLEditUtils::IsHeader(prevItem))
|
||||
{
|
||||
PRBool bIsEmptyNode;
|
||||
|
@ -2749,7 +2811,7 @@ nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection,
|
|||
// layout tells the caret to blink in a weird place
|
||||
// if we dont place a break after the header.
|
||||
nsCOMPtr<nsIDOMNode> sibling;
|
||||
res = GetNextHTMLSibling(headerParent, offset+1, &sibling);
|
||||
res = mEditor->GetNextHTMLSibling(headerParent, offset+1, &sibling);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!sibling || !nsHTMLEditUtils::IsBreak(sibling))
|
||||
{
|
||||
|
@ -2801,7 +2863,7 @@ nsHTMLEditRules::ReturnInParagraph(nsIDOMSelection *aSelection,
|
|||
if (!aOffset)
|
||||
{
|
||||
// is there a BR prior to it?
|
||||
GetPriorHTMLSibling(aNode, &sibling);
|
||||
mEditor->GetPriorHTMLSibling(aNode, &sibling);
|
||||
if (!sibling)
|
||||
{
|
||||
// no previous sib, so
|
||||
|
@ -2829,7 +2891,7 @@ nsHTMLEditRules::ReturnInParagraph(nsIDOMSelection *aSelection,
|
|||
if (aOffset == (PRInt32)strLength)
|
||||
{
|
||||
// is there a BR after to it?
|
||||
res = GetNextHTMLSibling(aNode, &sibling);
|
||||
res = mEditor->GetNextHTMLSibling(aNode, &sibling);
|
||||
if (!sibling)
|
||||
{
|
||||
// no next sib, so
|
||||
|
@ -2862,13 +2924,13 @@ nsHTMLEditRules::ReturnInParagraph(nsIDOMSelection *aSelection,
|
|||
// not in a text node.
|
||||
// is there a BR prior to it?
|
||||
nsCOMPtr<nsIDOMNode> nearNode;
|
||||
res = GetPriorHTMLNode(aNode, aOffset, &nearNode);
|
||||
res = mEditor->GetPriorHTMLNode(aNode, aOffset, &nearNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!nearNode || !nsHTMLEditUtils::IsBreak(nearNode)
|
||||
|| nsHTMLEditUtils::HasMozAttr(nearNode))
|
||||
{
|
||||
// is there a BR after to it?
|
||||
res = GetNextHTMLNode(aNode, aOffset, &nearNode);
|
||||
res = mEditor->GetNextHTMLNode(aNode, aOffset, &nearNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!nearNode || !nsHTMLEditUtils::IsBreak(nearNode)
|
||||
|| nsHTMLEditUtils::HasMozAttr(nearNode))
|
||||
|
@ -2928,7 +2990,7 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,
|
|||
|
||||
// are we the last list item in the list?
|
||||
PRBool bIsLast;
|
||||
res = IsLastEditableChild(aListItem, &bIsLast);
|
||||
res = mEditor->IsLastEditableChild(aListItem, &bIsLast);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!bIsLast)
|
||||
{
|
||||
|
@ -2971,7 +3033,7 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,
|
|||
// extra inclusive, I have to manually detect certain list items that
|
||||
// may be left empty.
|
||||
nsCOMPtr<nsIDOMNode> prevItem;
|
||||
GetPriorHTMLSibling(aListItem, &prevItem);
|
||||
mEditor->GetPriorHTMLSibling(aListItem, &prevItem);
|
||||
if (prevItem && nsHTMLEditUtils::IsListItem(prevItem))
|
||||
{
|
||||
PRBool bIsEmptyNode;
|
||||
|
@ -3322,9 +3384,9 @@ nsHTMLEditRules::JoinNodesSmart( nsIDOMNode *aNodeLeft,
|
|||
{
|
||||
// remember the last left child, and firt right child
|
||||
nsCOMPtr<nsIDOMNode> lastLeft, firstRight;
|
||||
res = GetLastEditableChild(aNodeLeft, &lastLeft);
|
||||
res = mEditor->GetLastEditableChild(aNodeLeft, &lastLeft);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = GetFirstEditableChild(aNodeRight, &firstRight);
|
||||
res = mEditor->GetFirstEditableChild(aNodeRight, &firstRight);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// for list items, divs, etc, merge smart
|
||||
|
@ -3555,7 +3617,7 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
|
|||
// 4) that br is the last editable node in it's block
|
||||
|
||||
nsCOMPtr<nsIDOMNode> nearNode;
|
||||
res = GetPriorHTMLNode(selNode, selOffset, &nearNode);
|
||||
res = mEditor->GetPriorHTMLNode(selNode, selOffset, &nearNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!nearNode) return res;
|
||||
|
||||
|
@ -3570,7 +3632,7 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
|
|||
&& !nsHTMLEditUtils::IsMozBR(nearNode))
|
||||
{
|
||||
PRBool bIsLast;
|
||||
res = IsLastEditableChild(nearNode, &bIsLast);
|
||||
res = mEditor->IsLastEditableChild(nearNode, &bIsLast);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (bIsLast)
|
||||
{
|
||||
|
@ -3594,9 +3656,9 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
|
|||
// <body> text<br> <ol><li>list item</li></ol></body> )
|
||||
// in this case we also need moz-br.
|
||||
nsCOMPtr<nsIDOMNode> nextNode;
|
||||
res = GetNextHTMLNode(nearNode, &nextNode);
|
||||
res = mEditor->GetNextHTMLNode(nearNode, &nextNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = GetNextHTMLSibling(nearNode, &nextNode);
|
||||
res = mEditor->GetNextHTMLSibling(nearNode, &nextNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (nextNode && mEditor->IsBlockNode(nextNode))
|
||||
{
|
||||
|
@ -3617,12 +3679,12 @@ nsHTMLEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirect
|
|||
}
|
||||
|
||||
// we aren't in a textnode: are we adjacent to a break or an image?
|
||||
res = GetPriorHTMLSibling(selNode, selOffset, &nearNode);
|
||||
res = mEditor->GetPriorHTMLSibling(selNode, selOffset, &nearNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (nearNode && (nsHTMLEditUtils::IsBreak(nearNode)
|
||||
|| nsHTMLEditUtils::IsImage(nearNode)))
|
||||
return NS_OK; // this is a good place for the caret to be
|
||||
res = GetNextHTMLSibling(selNode, selOffset, &nearNode);
|
||||
res = mEditor->GetNextHTMLSibling(selNode, selOffset, &nearNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (nearNode && (nsHTMLEditUtils::IsBreak(nearNode)
|
||||
|| nsHTMLEditUtils::IsImage(nearNode)))
|
||||
|
@ -3668,9 +3730,9 @@ nsHTMLEditRules::FindNearSelectableNode(nsIDOMNode *aSelNode,
|
|||
|
||||
nsCOMPtr<nsIDOMNode> nearNode, curNode;
|
||||
if (aDirection == nsIEditor::ePrevious)
|
||||
res = GetPriorHTMLNode(aSelNode, aSelOffset, &nearNode);
|
||||
res = mEditor->GetPriorHTMLNode(aSelNode, aSelOffset, &nearNode);
|
||||
else
|
||||
res = GetNextHTMLNode(aSelNode, aSelOffset, &nearNode);
|
||||
res = mEditor->GetNextHTMLNode(aSelNode, aSelOffset, &nearNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// scan in the right direction until we find an eligible text node,
|
||||
|
@ -3685,9 +3747,9 @@ nsHTMLEditRules::FindNearSelectableNode(nsIDOMNode *aSelNode,
|
|||
|
||||
curNode = nearNode;
|
||||
if (aDirection == nsIEditor::ePrevious)
|
||||
res = GetPriorHTMLNode(curNode, &nearNode);
|
||||
res = mEditor->GetPriorHTMLNode(curNode, &nearNode);
|
||||
else
|
||||
res = GetNextHTMLNode(curNode, &nearNode);
|
||||
res = mEditor->GetNextHTMLNode(curNode, &nearNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
|
@ -4011,11 +4073,11 @@ nsHTMLEditRules::PopListItem(nsIDOMNode *aListItem, PRBool *aOutOfList)
|
|||
if (NS_FAILED(res)) return res;
|
||||
|
||||
PRBool bIsFirstListItem;
|
||||
res = IsFirstEditableChild(curNode, &bIsFirstListItem);
|
||||
res = mEditor->IsFirstEditableChild(curNode, &bIsFirstListItem);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
PRBool bIsLastListItem;
|
||||
res = IsLastEditableChild(curNode, &bIsLastListItem);
|
||||
res = mEditor->IsLastEditableChild(curNode, &bIsLastListItem);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
if (!bIsFirstListItem && !bIsLastListItem)
|
||||
|
@ -4036,7 +4098,7 @@ nsHTMLEditRules::PopListItem(nsIDOMNode *aListItem, PRBool *aOutOfList)
|
|||
&& nsHTMLEditUtils::IsListItem(curNode))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> lastChild;
|
||||
res = GetLastEditableChild(curNode, &lastChild);
|
||||
res = mEditor->GetLastEditableChild(curNode, &lastChild);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->RemoveContainer(curNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
|
|
@ -85,7 +85,6 @@ protected:
|
|||
PRBool *aHandled,
|
||||
const nsString *inString,
|
||||
nsString *outString,
|
||||
TypeInState typeInState,
|
||||
PRInt32 aMaxLength);
|
||||
nsresult WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillDeleteSelection(nsIDOMSelection *aSelection, nsIEditor::EDirection aAction,
|
||||
|
@ -107,6 +106,7 @@ protected:
|
|||
nsresult ReturnInParagraph(nsIDOMSelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult ReturnInListItem(nsIDOMSelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset);
|
||||
|
||||
nsresult CreateStyleForInsertText(nsIDOMSelection *aSelection, nsIDOMDocument *aDoc);
|
||||
nsresult IsEmptyBlock(nsIDOMNode *aNode,
|
||||
PRBool *outIsEmptyBlock,
|
||||
PRBool aMozBRDoesntCount = PR_FALSE,
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -281,12 +281,30 @@ public:
|
|||
/** make the given selection span the entire document */
|
||||
NS_IMETHOD SelectEntireDocument(nsIDOMSelection *aSelection);
|
||||
|
||||
/** join together any afjacent editable text nodes in the range */
|
||||
NS_IMETHOD CollapseAdjacentTextNodes(nsIDOMRange *aInRange);
|
||||
|
||||
/* ------------ nsICSSLoaderObserver -------------- */
|
||||
NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet*aSheet, PRBool aNotify);
|
||||
|
||||
/* ------------ Utility Routines, not part of public API -------------- */
|
||||
NS_IMETHOD GetBodyStyleContext(nsIStyleContext** aStyleContext);
|
||||
|
||||
/** returns the absolute position of the end points of aSelection
|
||||
* in the document as a text stream.
|
||||
*/
|
||||
nsresult GetTextSelectionOffsets(nsIDOMSelection *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();
|
||||
|
@ -306,8 +324,6 @@ protected:
|
|||
*/
|
||||
NS_IMETHOD GetLayoutObject(nsIDOMNode *aInNode, nsISupports **aOutLayoutObject);
|
||||
|
||||
NS_IMETHOD CollapseAdjacentTextNodes(nsIDOMSelection *aInSelection);
|
||||
|
||||
NS_IMETHOD DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNode> &parentSelectedNode, PRInt32& offsetOfNewNode);
|
||||
|
||||
/* StyleSheet load callback */
|
||||
|
@ -325,10 +341,6 @@ protected:
|
|||
void CacheInlineStyles(nsIDOMNode *aNode);
|
||||
void ClearInlineStylesCache();
|
||||
|
||||
// typing state getters
|
||||
NS_IMETHOD GetTypingState(nsIAtom *aProperty, PRBool &aPropIsSet, PRBool &aSetting);
|
||||
NS_IMETHOD GetTypingStateValue(nsIAtom *aProperty, PRBool &aPropIsSet, nsString &aValue);
|
||||
|
||||
// key event helpers
|
||||
NS_IMETHOD TabInTable(PRBool inIsShift, PRBool *outHandled);
|
||||
NS_IMETHOD CreateBR(nsIDOMNode *aNode, PRInt32 aOffset,
|
||||
|
@ -371,37 +383,10 @@ protected:
|
|||
// failed to set selection to some other content in the document
|
||||
NS_IMETHOD SetSelectionAtDocumentStart(nsIDOMSelection *aSelection);
|
||||
|
||||
|
||||
// End of Table Editing utilities
|
||||
|
||||
|
||||
NS_IMETHOD ReParentContentOfNode(nsIDOMNode *aNode,
|
||||
nsString &aParentTag,
|
||||
BlockTransformationType aTranformation);
|
||||
|
||||
NS_IMETHOD ReParentBlockContent(nsIDOMNode *aNode,
|
||||
nsString &aParentTag,
|
||||
nsIDOMNode *aBlockParentNode,
|
||||
nsString &aBlockParentTag,
|
||||
BlockTransformationType aTranformation,
|
||||
nsIDOMNode **aNewParentNode);
|
||||
|
||||
/* NS_IMETHOD ReParentContentOfRange(nsIDOMRange *aRange,
|
||||
nsString &aParentTag,
|
||||
BlockTransformationType aTranformation);
|
||||
*/
|
||||
NS_IMETHOD RemoveParagraphStyleFromRange(nsIDOMRange *aRange);
|
||||
|
||||
NS_IMETHOD RemoveParagraphStyleFromBlockContent(nsIDOMRange *aRange);
|
||||
|
||||
NS_IMETHOD RemoveParentFromRange(const nsString &aParentTag, nsIDOMRange *aRange);
|
||||
|
||||
NS_IMETHOD RemoveParentFromBlockContent(const nsString &aParentTag, nsIDOMRange *aRange);
|
||||
|
||||
NS_IMETHOD IsRootTag(nsString &aTag, PRBool &aIsTag);
|
||||
|
||||
NS_IMETHOD IsLeafThatTakesInlineStyle(const nsString *aTag, PRBool &aResult);
|
||||
|
||||
NS_IMETHOD IsSubordinateBlock(nsString &aTag, PRBool &aIsTag);
|
||||
|
||||
static PRBool IsTable(nsIDOMNode *aNode);
|
||||
|
@ -439,133 +424,18 @@ protected:
|
|||
const nsString *aAttributes,
|
||||
PRBool &aIsSet) const;
|
||||
|
||||
/** Moves the content between (aNode, aStartOffset) and (aNode, aEndOffset)
|
||||
* into aNewParentNode, splitting aNode as necessary to maintain the relative
|
||||
* position of all leaf content.
|
||||
* @param aNode The node whose content we're repositioning.
|
||||
* aNode can be either a text node or a container node.
|
||||
* @param aNewParentNode The node that will be the repositioned contents' parent.
|
||||
* The caller is responsible for allocating aNewParentNode
|
||||
* @param aStartOffset The start offset of the content of aNode
|
||||
* @param aEndOffset The end offset of the content of aNode.
|
||||
*/
|
||||
NS_IMETHOD MoveContentOfNodeIntoNewParent(nsIDOMNode *aNode,
|
||||
nsIDOMNode *aNewParentNode,
|
||||
PRInt32 aStartOffset,
|
||||
PRInt32 aEndOffset);
|
||||
|
||||
/** Moves the content between (aStartNode, aStartOffset) and (aEndNode, aEndOffset)
|
||||
* into aNewParentNode, splitting aStartNode and aEndNode as necessary to maintain
|
||||
* the relative position of all leaf content.
|
||||
* The content between the two endpoints MUST be "contiguous" in the sense that
|
||||
* it is all in the same block. Another way of saying this is all content nodes
|
||||
* between aStartNode and aEndNode must be inline.
|
||||
* @see IntermediateNodesAreInline
|
||||
*
|
||||
* @param aStartNode The left node, can be either a text node or a container node.
|
||||
* @param aStartOffset The start offset in the content of aStartNode
|
||||
* @param aEndNode The right node, can be either a text node or a container node.
|
||||
* @param aEndOffset The end offset in the content of aEndNode.
|
||||
* @param aGrandParentNode The common ancestor of aStartNode and aEndNode.
|
||||
* aGrandParentNode will be the parent of aNewParentNode.
|
||||
* @param aNewParentNode The node that will be the repositioned contents' parent.
|
||||
* The caller is responsible for allocating aNewParentNode
|
||||
*/
|
||||
NS_IMETHOD MoveContiguousContentIntoNewParent(nsIDOMNode *aStartNode,
|
||||
PRInt32 aStartOffset,
|
||||
nsIDOMNode *aEndNode,
|
||||
PRInt32 aEndOffset,
|
||||
nsIDOMNode *aGrandParentNode,
|
||||
nsIDOMNode *aNewParentNode);
|
||||
|
||||
|
||||
NS_IMETHOD SetTextPropertiesForNode(nsIDOMNode *aNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aStartOffset,
|
||||
PRInt32 aEndOffset,
|
||||
nsIAtom *aPropName,
|
||||
const nsString *aAttribute,
|
||||
const nsString *aValue);
|
||||
|
||||
NS_IMETHOD SetTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode,
|
||||
PRInt32 aStartOffset,
|
||||
nsIDOMNode *aEndNode,
|
||||
PRInt32 aEndOffset,
|
||||
nsIDOMNode *aParent,
|
||||
nsIAtom *aPropName,
|
||||
const nsString *aAttribute,
|
||||
const nsString *aValue);
|
||||
|
||||
NS_IMETHOD SetTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRange,
|
||||
nsIDOMNode *aStartNode,
|
||||
PRInt32 aStartOffset,
|
||||
nsIDOMNode *aEndNode,
|
||||
PRInt32 aEndOffset,
|
||||
nsIDOMNode *aParent,
|
||||
nsIAtom *aPropName,
|
||||
const nsString *aAttribute,
|
||||
const nsString *aValue);
|
||||
|
||||
NS_IMETHOD RemoveTextPropertiesForNode(nsIDOMNode *aNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aStartOffset,
|
||||
PRInt32 aEndOffset,
|
||||
nsIAtom *aPropName,
|
||||
const nsString *aAttribute);
|
||||
|
||||
NS_IMETHOD RemoveTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode,
|
||||
PRInt32 aStartOffset,
|
||||
nsIDOMNode *aEndNode,
|
||||
PRInt32 aEndOffset,
|
||||
nsIDOMNode *aParent,
|
||||
nsIAtom *aPropName,
|
||||
const nsString *aAttribute);
|
||||
|
||||
NS_IMETHOD RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStartNode,
|
||||
PRInt32 aStartOffset,
|
||||
nsIDOMNode *aEndNode,
|
||||
PRInt32 aEndOffset,
|
||||
nsIDOMNode *aParent,
|
||||
nsIAtom *aPropName,
|
||||
const nsString *aAttribute);
|
||||
|
||||
NS_IMETHOD SetTypeInStateForProperty(TypeInState &aTypeInState,
|
||||
nsIAtom *aPropName,
|
||||
const nsString *aAttribute,
|
||||
const nsString *aValue);
|
||||
|
||||
NS_IMETHOD GetTextSelectionOffsetsForRange(nsIDOMSelection *aSelection,
|
||||
nsIDOMNode **aParent,
|
||||
PRInt32 &aStartOffset,
|
||||
PRInt32 &aEndOffset);
|
||||
|
||||
void ResetTextSelectionForRange(nsIDOMNode *aParent,
|
||||
PRInt32 aStartOffset,
|
||||
PRInt32 aEndOffset,
|
||||
nsIDOMSelection *aSelection);
|
||||
|
||||
/** returns the absolute position of the end points of aSelection
|
||||
* in the document as a text stream.
|
||||
*/
|
||||
nsresult GetTextSelectionOffsets(nsIDOMSelection *aSelection,
|
||||
PRInt32 &aStartOffset,
|
||||
PRInt32 &aEndOffset);
|
||||
|
||||
nsresult GetAbsoluteOffsetsForPoints(nsIDOMNode *aInStartNode,
|
||||
PRInt32 aInStartOffset,
|
||||
nsIDOMNode *aInEndNode,
|
||||
PRInt32 aInEndOffset,
|
||||
nsIDOMNode *aInCommonParentNode,
|
||||
PRInt32 &aOutStartOffset,
|
||||
PRInt32 &aEndOffset);
|
||||
|
||||
// Methods for handling plaintext quotations
|
||||
NS_IMETHOD PasteAsPlaintextQuotation();
|
||||
NS_IMETHOD InsertAsPlaintextQuotation(const nsString& aQuotedText,
|
||||
nsIDOMNode **aNodeInserted);
|
||||
|
||||
TypeInState *GetTypeInState();
|
||||
|
||||
/** simple utility to handle any error with event listener allocation or registration */
|
||||
void HandleEventListenerError();
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "nsIEditProperty.h"
|
||||
#include "nsEditorUtils.h"
|
||||
#include "EditTxn.h"
|
||||
#include "TypeInState.h"
|
||||
|
||||
static NS_DEFINE_CID(kContentIteratorCID, NS_CONTENTITERATOR_CID);
|
||||
static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
|
||||
|
@ -227,7 +228,6 @@ nsTextEditRules::WillDoAction(nsIDOMSelection *aSelection,
|
|||
aHandled,
|
||||
info->inString,
|
||||
info->outString,
|
||||
info->typeInState,
|
||||
info->maxLength);
|
||||
case kDeleteSelection:
|
||||
return WillDeleteSelection(aSelection, info->collapsedAction, aCancel, aHandled);
|
||||
|
@ -340,7 +340,7 @@ nsTextEditRules::WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel)
|
|||
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// get prior node
|
||||
res = GetPriorHTMLNode(selNode, selOffset, &priorNode);
|
||||
res = mEditor->GetPriorHTMLNode(selNode, selOffset, &priorNode);
|
||||
if (NS_SUCCEEDED(res) && priorNode && nsHTMLEditUtils::IsMozBR(priorNode))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> block1, block2;
|
||||
|
@ -487,12 +487,12 @@ nsTextEditRules::DidInsertBreak(nsIDOMSelection *aSelection, nsresult aResult)
|
|||
nsresult res;
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = GetPriorHTMLNode(selNode, selOffset, &nearNode);
|
||||
res = mEditor->GetPriorHTMLNode(selNode, selOffset, &nearNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (nearNode && nsHTMLEditUtils::IsBreak(nearNode) && !nsHTMLEditUtils::IsMozBR(nearNode))
|
||||
{
|
||||
PRBool bIsLast;
|
||||
res = IsLastEditableChild(nearNode, &bIsLast);
|
||||
res = mEditor->IsLastEditableChild(nearNode, &bIsLast);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (bIsLast)
|
||||
{
|
||||
|
@ -514,18 +514,15 @@ nsTextEditRules::DidInsertBreak(nsIDOMSelection *aSelection, nsresult aResult)
|
|||
nsresult
|
||||
nsTextEditRules::WillInsertText(PRInt32 aAction,
|
||||
nsIDOMSelection *aSelection,
|
||||
PRBool *aCancel,
|
||||
PRBool *aCancel,
|
||||
PRBool *aHandled,
|
||||
const nsString *aInString,
|
||||
nsString *aOutString,
|
||||
TypeInState aTypeInState,
|
||||
const nsString *inString,
|
||||
nsString *outString,
|
||||
PRInt32 aMaxLength)
|
||||
{
|
||||
if (!aSelection || !aCancel || !aHandled || !aInString || !aOutString)
|
||||
{return NS_ERROR_NULL_POINTER;}
|
||||
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
|
||||
{
|
||||
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
if (aInString->IsEmpty() && (aAction != kInsertTextIME))
|
||||
if (inString->IsEmpty() && (aAction != kInsertTextIME))
|
||||
{
|
||||
// HACK: this is a fix for bug 19395
|
||||
// I can't outlaw all empty insertions
|
||||
|
@ -536,28 +533,16 @@ nsTextEditRules::WillInsertText(PRInt32 aAction,
|
|||
*aHandled = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult res;
|
||||
|
||||
// initialize out params
|
||||
|
||||
// initialize out param
|
||||
*aCancel = PR_FALSE;
|
||||
*aHandled = PR_TRUE;
|
||||
*aOutString = *aInString;
|
||||
PRInt32 start=0; PRInt32 end=0;
|
||||
nsresult res;
|
||||
nsCOMPtr<nsIDOMNode> selNode;
|
||||
PRInt32 selOffset;
|
||||
|
||||
// handle docs with a max length
|
||||
res = TruncateInsertionIfNeeded(aSelection, aInString, aOutString, aMaxLength);
|
||||
if (NS_FAILED(res)) return res;
|
||||
char specialChars[] = {'\t','\n',0};
|
||||
|
||||
// handle password field docs
|
||||
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
||||
{
|
||||
res = mEditor->GetTextSelectionOffsets(aSelection, start, end);
|
||||
NS_ASSERTION((NS_SUCCEEDED(res)), "getTextSelectionOffsets failed!");
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
|
||||
// if the selection isn't collapsed, delete it.
|
||||
PRBool bCollapsed;
|
||||
res = aSelection->GetIsCollapsed(&bCollapsed);
|
||||
|
@ -573,69 +558,132 @@ nsTextEditRules::WillInsertText(PRInt32 aAction,
|
|||
// initialize out param
|
||||
// we want to ignore result of WillInsert()
|
||||
*aCancel = PR_FALSE;
|
||||
|
||||
// get the (collapsed) selection location
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// handle password field data
|
||||
// this has the side effect of changing all the characters in aOutString
|
||||
// to the replacement character
|
||||
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
||||
{
|
||||
res = EchoInsertionToPWBuff(start, end, aOutString);
|
||||
// dont put text in places that cant have it
|
||||
nsAutoString textTag = "__moz_text";
|
||||
if (!mEditor->IsTextNode(selNode) && !mEditor->CanContainTag(selNode, textTag))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// we need to get the doc
|
||||
nsCOMPtr<nsIDOMDocument>doc;
|
||||
res = mEditor->GetDocument(getter_AddRefs(doc));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!doc) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (aAction == kInsertTextIME)
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(*inString, &selNode, &selOffset, doc);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
// if we're a single line control, pretreat the input string to remove returns
|
||||
// this is unnecessary if we use <BR>'s for breaks in "plain text", because
|
||||
// InsertBreak() checks the string. But we don't currently do that, so we need this
|
||||
// fixes bug 21032
|
||||
// *** there's some debate about whether we should replace CRLF with spaces, or
|
||||
// truncate the string at the first CRLF. Here, we replace with spaces.
|
||||
// Hack: I stripped out this test for IME inserts - it screws up double byte chars
|
||||
// that happen to end in the same values as CR or LF. Bug 27699
|
||||
if (aInString->IsEmpty() && (aAction != kInsertTextIME))
|
||||
if ((nsIHTMLEditor::eEditorSingleLineMask & mFlags) && (aAction != kInsertTextIME))
|
||||
else // aAction == kInsertText
|
||||
{
|
||||
aOutString->ReplaceChar(CRLF, ' ');
|
||||
}
|
||||
|
||||
// time to do actual text insertion ------------------------------
|
||||
|
||||
PRBool bCancel;
|
||||
char newlineChar[] = {'\n',0};
|
||||
nsString theString(*aOutString); // copy instring for now
|
||||
|
||||
// do the text insertion (IME case)
|
||||
if(aAction == kInsertTextIME)
|
||||
{
|
||||
// special case for IME. We need this to
|
||||
// handle null strings, which are meaningful for IME
|
||||
res = DoTextInsertion(aSelection, &bCancel, &theString, aTypeInState);
|
||||
return res;
|
||||
}
|
||||
|
||||
// do text insertion (non-IME case)
|
||||
while (theString.Length())
|
||||
{
|
||||
nsString partialString;
|
||||
PRInt32 pos = theString.FindCharInSet(newlineChar);
|
||||
// if first char is special, then use just it
|
||||
if (pos == 0) pos = 1;
|
||||
if (pos == -1) pos = theString.Length();
|
||||
theString.Left(partialString, pos);
|
||||
theString.Cut(0, pos);
|
||||
|
||||
// is it a solo return?
|
||||
if (partialString.Equals("\n"))
|
||||
// find where we are
|
||||
nsCOMPtr<nsIDOMNode> curNode = selNode;
|
||||
PRInt32 curOffset = selOffset;
|
||||
|
||||
// is our text going to be PREformatted?
|
||||
// We remember this so that we know how to handle tabs.
|
||||
PRBool isPRE;
|
||||
res = mEditor->IsPreformatted(selNode, &isPRE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// dont spaz my selection in subtransactions
|
||||
nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
|
||||
nsSubsumeStr subStr;
|
||||
const PRUnichar *unicodeBuf = inString->GetUnicode();
|
||||
nsCOMPtr<nsIDOMNode> unused;
|
||||
PRInt32 pos = 0;
|
||||
|
||||
// for efficiency, break out the pre case seperately. This is because
|
||||
// its a lot cheaper to search the input string for only newlines than
|
||||
// it is to search for both tabs and newlines.
|
||||
if (isPRE)
|
||||
{
|
||||
res = mEditor->InsertBreak();
|
||||
char newlineChar = '\n';
|
||||
while (unicodeBuf && (pos != -1) && (pos < inString->Length()))
|
||||
{
|
||||
PRInt32 oldPos = pos;
|
||||
PRInt32 subStrLen;
|
||||
pos = inString->FindChar(newlineChar, PR_FALSE, oldPos);
|
||||
|
||||
if (pos != -1)
|
||||
{
|
||||
subStrLen = pos - oldPos;
|
||||
// if first char is newline, then use just it
|
||||
if (subStrLen == 0)
|
||||
subStrLen = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
subStrLen = inString->Length() - oldPos;
|
||||
pos = inString->Length();
|
||||
}
|
||||
|
||||
subStr.Subsume((PRUnichar*)&unicodeBuf[oldPos], PR_FALSE, subStrLen);
|
||||
|
||||
// is it a return?
|
||||
if (subStr.Equals("\n"))
|
||||
{
|
||||
res = mEditor->JoeCreateBR(&curNode, &curOffset, &unused, nsIEditor::eNone);
|
||||
pos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(subStr, &curNode, &curOffset, doc);
|
||||
}
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
res = DoTextInsertion(aSelection, &bCancel, &partialString, aTypeInState);
|
||||
}
|
||||
if (NS_FAILED(res)) return res;
|
||||
pos = theString.FindCharInSet(newlineChar);
|
||||
}
|
||||
char specialChars[] = {'\t','\n',0};
|
||||
nsAutoString tabString = " ";
|
||||
while (unicodeBuf && (pos != -1) && (pos < inString->Length()))
|
||||
{
|
||||
PRInt32 oldPos = pos;
|
||||
PRInt32 subStrLen;
|
||||
pos = inString->FindCharInSet(specialChars, oldPos);
|
||||
|
||||
if (pos != -1)
|
||||
{
|
||||
subStrLen = pos - oldPos;
|
||||
// if first char is newline, then use just it
|
||||
if (subStrLen == 0)
|
||||
subStrLen = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
subStrLen = inString->Length() - oldPos;
|
||||
pos = inString->Length();
|
||||
}
|
||||
|
||||
subStr.Subsume((PRUnichar*)&unicodeBuf[oldPos], PR_FALSE, subStrLen);
|
||||
|
||||
// is it a tab?
|
||||
if (subStr.Equals("\t"))
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(tabString, &curNode, &curOffset, doc);
|
||||
pos++;
|
||||
}
|
||||
// is it a return?
|
||||
else if (subStr.Equals("\n"))
|
||||
{
|
||||
res = mEditor->JoeCreateBR(&curNode, &curOffset, &unused, nsIEditor::eNone);
|
||||
pos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mEditor->JoeInsertTextImpl(subStr, &curNode, &curOffset, doc);
|
||||
}
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
if (curNode) aSelection->Collapse(curNode, curOffset);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -646,375 +694,7 @@ nsTextEditRules::DidInsertText(nsIDOMSelection *aSelection,
|
|||
return DidInsert(aSelection, aResult);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInState &aTypeInState)
|
||||
{
|
||||
// private method, we know aSelection is not null, and that it is collapsed
|
||||
NS_ASSERTION(nsnull!=aSelection, "bad selection");
|
||||
|
||||
// We know at least one style is set and we're about to insert at least one character.
|
||||
// If the selection is in a text node, split the node (even if we're at the beginning or end)
|
||||
// then put the text node inside new inline style parents.
|
||||
// Otherwise, create the text node and the new inline style parents.
|
||||
nsCOMPtr<nsIDOMNode>anchor;
|
||||
PRInt32 offset;
|
||||
nsresult res = aSelection->GetAnchorNode( getter_AddRefs(anchor));
|
||||
// createNewTextNode is a flag that tells us whether we need to create a new text node or not
|
||||
PRBool createNewTextNode = PR_TRUE;
|
||||
if (NS_SUCCEEDED(res) && NS_SUCCEEDED(aSelection->GetAnchorOffset(&offset)) && anchor)
|
||||
{
|
||||
nsCOMPtr<nsIDOMCharacterData>anchorAsText;
|
||||
anchorAsText = do_QueryInterface(anchor);
|
||||
if (anchorAsText)
|
||||
{
|
||||
createNewTextNode = PR_FALSE; // we found a text node, we'll base our insertion on it
|
||||
nsCOMPtr<nsIDOMNode>newTextNode;
|
||||
// create an empty text node by splitting the selected text node according to offset
|
||||
if (0==offset)
|
||||
{
|
||||
res = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
|
||||
}
|
||||
else
|
||||
{
|
||||
PRUint32 length;
|
||||
anchorAsText->GetLength(&length);
|
||||
if (length==(PRUint32)offset)
|
||||
{
|
||||
// newTextNode will be the left node
|
||||
res = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
|
||||
// but we want the right node in this case
|
||||
newTextNode = do_QueryInterface(anchor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// splitting anchor twice sets newTextNode as an empty text node between
|
||||
// two halves of the original text node
|
||||
res = mEditor->SplitNode(anchorAsText, offset, getter_AddRefs(newTextNode));
|
||||
if (NS_SUCCEEDED(res)) {
|
||||
res = mEditor->SplitNode(anchorAsText, 0, getter_AddRefs(newTextNode));
|
||||
}
|
||||
}
|
||||
}
|
||||
// now we have the new text node we are going to insert into.
|
||||
// create style nodes or move it up the content hierarchy as needed.
|
||||
if ((NS_SUCCEEDED(res)) && newTextNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>newStyleNode;
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_BOLD))
|
||||
{
|
||||
if (PR_TRUE==aTypeInState.GetBold()) {
|
||||
res = InsertStyleNode(newTextNode, nsIEditProperty::b, aSelection, getter_AddRefs(newStyleNode));
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>parent;
|
||||
res = newTextNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_NULL_POINTER;
|
||||
res = mEditor->RemoveTextPropertiesForNode (newTextNode, parent, 0, 0, nsIEditProperty::b, nsnull);
|
||||
}
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_ITALIC))
|
||||
{
|
||||
if (PR_TRUE==aTypeInState.GetItalic()) {
|
||||
res = InsertStyleNode(newTextNode, nsIEditProperty::i, aSelection, getter_AddRefs(newStyleNode));
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>parent;
|
||||
res = newTextNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_NULL_POINTER;
|
||||
res = mEditor->RemoveTextPropertiesForNode (newTextNode, parent, 0, 0, nsIEditProperty::i, nsnull);
|
||||
}
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_UNDERLINE))
|
||||
{
|
||||
if (PR_TRUE==aTypeInState.GetUnderline()) {
|
||||
res = InsertStyleNode(newTextNode, nsIEditProperty::u, aSelection, getter_AddRefs(newStyleNode));
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>parent;
|
||||
res = newTextNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_NULL_POINTER;
|
||||
res = mEditor->RemoveTextPropertiesForNode (newTextNode, parent, 0, 0, nsIEditProperty::u, nsnull);
|
||||
}
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTCOLOR))
|
||||
{
|
||||
nsAutoString value;
|
||||
aTypeInState.GetFontColor(value);
|
||||
nsAutoString attr;
|
||||
nsIEditProperty::color->ToString(attr);
|
||||
res = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTFACE))
|
||||
{
|
||||
nsAutoString value;
|
||||
aTypeInState.GetFontFace(value);
|
||||
nsAutoString attr;
|
||||
nsIEditProperty::face->ToString(attr);
|
||||
res = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTSIZE))
|
||||
{
|
||||
nsAutoString value;
|
||||
aTypeInState.GetFontSize(value);
|
||||
nsAutoString attr;
|
||||
nsIEditProperty::size->ToString(attr);
|
||||
res = CreateFontStyleForInsertText(newTextNode, attr, value, aSelection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we have no text node, so create a new style tag(s) with a newly created text node in it
|
||||
// this is a separate case from the code above because that code needs to handle turning
|
||||
// properties on and off, this code only turns them on
|
||||
if (PR_TRUE==createNewTextNode)
|
||||
{
|
||||
offset = 0;
|
||||
nsCOMPtr<nsIDOMNode>parent = do_QueryInterface(anchor);
|
||||
if (parent)
|
||||
{ // we have a selection, get the offset within the parent
|
||||
res = aSelection->GetAnchorOffset(&offset);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement> bodyElement;
|
||||
res = mEditor->GetBodyElement(getter_AddRefs(bodyElement));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!bodyElement) return NS_ERROR_NULL_POINTER;
|
||||
parent = do_QueryInterface(bodyElement);
|
||||
// offset already set to 0
|
||||
}
|
||||
if (!parent) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
nsAutoString attr, value;
|
||||
|
||||
// now we've got the parent. insert the style tag(s)
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_BOLD))
|
||||
{
|
||||
if (PR_TRUE==aTypeInState.GetBold()) {
|
||||
res = InsertStyleAndNewTextNode(parent, offset,
|
||||
nsIEditProperty::b, attr, value,
|
||||
aSelection);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
}
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_ITALIC))
|
||||
{
|
||||
if (PR_TRUE==aTypeInState.GetItalic()) {
|
||||
res = InsertStyleAndNewTextNode(parent, offset,
|
||||
nsIEditProperty::i, attr, value,
|
||||
aSelection);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
}
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_UNDERLINE))
|
||||
{
|
||||
if (PR_TRUE==aTypeInState.GetUnderline()) {
|
||||
res = InsertStyleAndNewTextNode(parent, offset,
|
||||
nsIEditProperty::u, attr, value,
|
||||
aSelection);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
}
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTCOLOR))
|
||||
{
|
||||
aTypeInState.GetFontColor(value);
|
||||
nsIEditProperty::color->ToString(attr);
|
||||
res = InsertStyleAndNewTextNode(parent, offset,
|
||||
nsIEditProperty::font, attr, value,
|
||||
aSelection);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTFACE))
|
||||
{
|
||||
aTypeInState.GetFontFace(value);
|
||||
nsIEditProperty::face->ToString(attr);
|
||||
res = InsertStyleAndNewTextNode(parent, offset,
|
||||
nsIEditProperty::font, attr, value,
|
||||
aSelection);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
}
|
||||
if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTSIZE))
|
||||
{
|
||||
aTypeInState.GetFontSize(value);
|
||||
nsIEditProperty::size->ToString(attr);
|
||||
res = InsertStyleAndNewTextNode(parent, offset,
|
||||
nsIEditProperty::font, attr, value,
|
||||
aSelection);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::CreateFontStyleForInsertText(nsIDOMNode *aNewTextNode,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue,
|
||||
nsIDOMSelection *aSelection)
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
nsCOMPtr<nsIDOMNode>newStyleNode;
|
||||
if (0!=aValue.Length())
|
||||
{
|
||||
res = InsertStyleNode(aNewTextNode, nsIEditProperty::font, aSelection, getter_AddRefs(newStyleNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!newStyleNode) return NS_ERROR_NULL_POINTER;
|
||||
nsCOMPtr<nsIDOMElement>element = do_QueryInterface(newStyleNode);
|
||||
if (element) {
|
||||
res = mEditor->SetAttribute(element, aAttr, aValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>parent;
|
||||
res = aNewTextNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_NULL_POINTER;
|
||||
res = mEditor->RemoveTextPropertiesForNode (aNewTextNode, parent, 0, 0, nsIEditProperty::font, &aAttr);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::InsertStyleNode(nsIDOMNode *aNode,
|
||||
nsIAtom *aTag,
|
||||
nsIDOMSelection *aSelection,
|
||||
nsIDOMNode **aNewNode)
|
||||
{
|
||||
NS_ASSERTION(aNode && aTag, "bad args");
|
||||
if (!aNode || !aTag) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
nsresult res;
|
||||
nsCOMPtr<nsIDOMNode>parent;
|
||||
res = aNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsAutoString tag;
|
||||
aTag->ToString(tag);
|
||||
|
||||
if (PR_FALSE == mEditor->CanContainTag(parent, tag)) {
|
||||
NS_ASSERTION(PR_FALSE, "bad use of InsertStyleNode");
|
||||
return NS_ERROR_FAILURE; // illegal place to insert the style tag
|
||||
}
|
||||
|
||||
PRInt32 offsetInParent;
|
||||
res = nsEditor::GetChildOffset(aNode, parent, offsetInParent);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
res = mEditor->CreateNode(tag, parent, offsetInParent, aNewNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!aNewNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
res = mEditor->DeleteNode(aNode);
|
||||
if (NS_SUCCEEDED(res))
|
||||
{
|
||||
res = mEditor->InsertNode(aNode, *aNewNode, 0);
|
||||
if (NS_SUCCEEDED(res)) {
|
||||
if (aSelection) {
|
||||
res = aSelection->Collapse(aNode, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::InsertStyleAndNewTextNode(nsIDOMNode *aParentNode,
|
||||
PRInt32 aOffset,
|
||||
nsIAtom *aTag,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue,
|
||||
nsIDOMSelection *aInOutSelection)
|
||||
{
|
||||
NS_ASSERTION(aParentNode && aTag, "bad args");
|
||||
if (!aParentNode || !aTag) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
nsresult res;
|
||||
// if the selection already points to a text node, just call InsertStyleNode()
|
||||
if (aInOutSelection)
|
||||
{
|
||||
PRBool isCollapsed;
|
||||
aInOutSelection->GetIsCollapsed(&isCollapsed);
|
||||
if (PR_TRUE==isCollapsed)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode>anchor;
|
||||
PRInt32 offset;
|
||||
res = aInOutSelection->GetAnchorNode(getter_AddRefs(anchor));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!anchor) return NS_ERROR_NULL_POINTER;
|
||||
res = aInOutSelection->GetAnchorOffset(&offset); // remember where we were
|
||||
if (NS_FAILED(res)) return res;
|
||||
// if we have a text node, just wrap it in a new style node
|
||||
if (PR_TRUE==mEditor->IsTextNode(anchor))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> newStyleNode;
|
||||
res = InsertStyleNode(anchor, aTag, aInOutSelection, getter_AddRefs(newStyleNode));
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
if (!newStyleNode) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
// if we were given an attribute, set it on the new style node
|
||||
PRInt32 attrLength = aAttr.Length();
|
||||
if (0!=attrLength)
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement>newStyleElement = do_QueryInterface(newStyleNode);
|
||||
res = mEditor->SetAttribute(newStyleElement, aAttr, aValue);
|
||||
}
|
||||
if (NS_SUCCEEDED(res)) {
|
||||
res = aInOutSelection->Collapse(anchor, offset);
|
||||
}
|
||||
return res; // we return here because we used the text node passed into us via collapsed selection
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we get here, there is no selected text node so we create one.
|
||||
// first, create the style node
|
||||
nsAutoString tag;
|
||||
aTag->ToString(tag);
|
||||
if (PR_FALSE == mEditor->CanContainTag(aParentNode, tag)) {
|
||||
NS_ASSERTION(PR_FALSE, "bad use of InsertStyleAndNewTextNode");
|
||||
return NS_ERROR_FAILURE; // illegal place to insert the style tag
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode>newStyleNode;
|
||||
nsCOMPtr<nsIDOMNode>newTextNode;
|
||||
res = mEditor->CreateNode(tag, aParentNode, aOffset, getter_AddRefs(newStyleNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!newStyleNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// if we were given an attribute, set it on the new style node
|
||||
PRInt32 attrLength = aAttr.Length();
|
||||
if (0!=attrLength)
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement>newStyleElement = do_QueryInterface(newStyleNode);
|
||||
res = mEditor->SetAttribute(newStyleElement, aAttr, aValue);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
// then create the text node
|
||||
nsAutoString textNodeTag;
|
||||
res = nsEditor::GetTextNodeTag(textNodeTag);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
|
||||
res = mEditor->CreateNode(textNodeTag, newStyleNode, 0, getter_AddRefs(newTextNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!newTextNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// if we have a selection collapse the selection to the beginning of the new text node
|
||||
if (aInOutSelection) {
|
||||
res = aInOutSelection->Collapse(newTextNode, 0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::WillSetTextProperty(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled)
|
||||
|
@ -1553,12 +1233,6 @@ nsTextEditRules::EchoInsertionToPWBuff(PRInt32 aStart, PRInt32 aEnd, nsString *a
|
|||
// manage the password buffer
|
||||
mPasswordText.Insert(*aOutString, aStart);
|
||||
|
||||
#ifdef DEBUG_jfrancis
|
||||
char *password = mPasswordText.ToNewCString();
|
||||
printf("mPasswordText is %s\n", password);
|
||||
nsCRT::free(password);
|
||||
#endif
|
||||
|
||||
// change the output to '*' only
|
||||
PRInt32 length = aOutString->Length();
|
||||
PRInt32 i;
|
||||
|
@ -1570,316 +1244,6 @@ nsTextEditRules::EchoInsertionToPWBuff(PRInt32 aStart, PRInt32 aEnd, nsString *a
|
|||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::DoTextInsertion(nsIDOMSelection *aSelection,
|
||||
PRBool *aCancel,
|
||||
const nsString *aInString,
|
||||
TypeInState aTypeInState)
|
||||
{
|
||||
if (!aSelection || !aCancel || !aInString) {return NS_ERROR_NULL_POINTER;}
|
||||
nsresult res = NS_OK;
|
||||
|
||||
// for now, we always cancel editor handling of insert text.
|
||||
// rules code always does the insertion
|
||||
*aCancel = PR_TRUE;
|
||||
|
||||
PRBool bCancel;
|
||||
res = WillInsert(aSelection, &bCancel);
|
||||
if (NS_SUCCEEDED(res) && (!bCancel))
|
||||
{
|
||||
if (PR_TRUE==aTypeInState.IsAnySet())
|
||||
{ // for every property that is set, insert a new inline style node
|
||||
res = CreateStyleForInsertText(aSelection, aTypeInState);
|
||||
if (NS_FAILED(res)) { return res; }
|
||||
}
|
||||
res = mEditor->InsertTextImpl(*aInString);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetPriorHTMLSibling: returns the previous editable sibling, if there is
|
||||
// one within the parent
|
||||
//
|
||||
nsresult
|
||||
nsTextEditRules::GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
|
||||
{
|
||||
if (!outNode || !inNode) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
*outNode = nsnull;
|
||||
nsCOMPtr<nsIDOMNode> temp, node = do_QueryInterface(inNode);
|
||||
|
||||
while (1)
|
||||
{
|
||||
res = node->GetPreviousSibling(getter_AddRefs(temp));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!temp) return NS_OK; // return null sibling
|
||||
// if it's editable, we're done
|
||||
if (mEditor->IsEditable(temp)) break;
|
||||
// otherwise try again
|
||||
node = temp;
|
||||
}
|
||||
*outNode = temp;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetPriorHTMLSibling: returns the previous editable sibling, if there is
|
||||
// one within the parent. just like above routine but
|
||||
// takes a parent/offset instead of a node.
|
||||
//
|
||||
nsresult
|
||||
nsTextEditRules::GetPriorHTMLSibling(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
|
||||
{
|
||||
if (!outNode || !inParent) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
*outNode = nsnull;
|
||||
if (!inOffset) return NS_OK; // return null sibling if at offset zero
|
||||
nsCOMPtr<nsIDOMNode> node = nsEditor::GetChildAt(inParent,inOffset-1);
|
||||
if (mEditor->IsEditable(node))
|
||||
{
|
||||
*outNode = node;
|
||||
return res;
|
||||
}
|
||||
// else
|
||||
return GetPriorHTMLSibling(node, outNode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetNextHTMLSibling: returns the next editable sibling, if there is
|
||||
// one within the parent
|
||||
//
|
||||
nsresult
|
||||
nsTextEditRules::GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
|
||||
{
|
||||
if (!outNode) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
*outNode = nsnull;
|
||||
nsCOMPtr<nsIDOMNode> temp, node = do_QueryInterface(inNode);
|
||||
|
||||
while (1)
|
||||
{
|
||||
res = node->GetNextSibling(getter_AddRefs(temp));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!temp) return NS_ERROR_FAILURE;
|
||||
// if it's editable, we're done
|
||||
if (mEditor->IsEditable(temp)) break;
|
||||
// otherwise try again
|
||||
node = temp;
|
||||
}
|
||||
*outNode = temp;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetNextHTMLSibling: returns the next editable sibling, if there is
|
||||
// one within the parent. just like above routine but
|
||||
// takes a parent/offset instead of a node.
|
||||
//
|
||||
nsresult
|
||||
nsTextEditRules::GetNextHTMLSibling(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
|
||||
{
|
||||
if (!outNode || !inParent) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
*outNode = nsnull;
|
||||
nsCOMPtr<nsIDOMNode> node = nsEditor::GetChildAt(inParent,inOffset);
|
||||
if (!node) return NS_OK; // return null sibling if no sibling
|
||||
if (mEditor->IsEditable(node))
|
||||
{
|
||||
*outNode = node;
|
||||
return res;
|
||||
}
|
||||
// else
|
||||
return GetPriorHTMLSibling(node, outNode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetPriorHTMLNode: returns the previous editable leaf node, if there is
|
||||
// one within the <body>
|
||||
//
|
||||
nsresult
|
||||
nsTextEditRules::GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
|
||||
{
|
||||
if (!outNode) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = mEditor->GetPriorNode(inNode, PR_TRUE, getter_AddRefs(*outNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// if it's not in the body, then zero it out
|
||||
if (*outNode && !nsHTMLEditUtils::InBody(*outNode))
|
||||
{
|
||||
*outNode = nsnull;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetPriorHTMLNode: same as above but takes {parent,offset} instead of node
|
||||
//
|
||||
nsresult
|
||||
nsTextEditRules::GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
|
||||
{
|
||||
if (!outNode) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = mEditor->GetPriorNode(inParent, inOffset, PR_TRUE, getter_AddRefs(*outNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// if it's not in the body, then zero it out
|
||||
if (*outNode && !nsHTMLEditUtils::InBody(*outNode))
|
||||
{
|
||||
*outNode = nsnull;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetNextHTMLNode: returns the previous editable leaf node, if there is
|
||||
// one within the <body>
|
||||
//
|
||||
nsresult
|
||||
nsTextEditRules::GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
|
||||
{
|
||||
if (!outNode) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = mEditor->GetNextNode(inNode, PR_TRUE, getter_AddRefs(*outNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// if it's not in the body, then zero it out
|
||||
if (*outNode && !nsHTMLEditUtils::InBody(*outNode))
|
||||
{
|
||||
*outNode = nsnull;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetNHTMLextNode: same as above but takes {parent,offset} instead of node
|
||||
//
|
||||
nsresult
|
||||
nsTextEditRules::GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
|
||||
{
|
||||
if (!outNode) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = mEditor->GetNextNode(inParent, inOffset, PR_TRUE, getter_AddRefs(*outNode));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// if it's not in the body, then zero it out
|
||||
if (*outNode && !nsHTMLEditUtils::InBody(*outNode))
|
||||
{
|
||||
*outNode = nsnull;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst)
|
||||
{
|
||||
// check parms
|
||||
if (!aOutIsFirst || !aNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// init out parms
|
||||
*aOutIsFirst = PR_FALSE;
|
||||
|
||||
// find first editable child and compare it to aNode
|
||||
nsCOMPtr<nsIDOMNode> parent, firstChild;
|
||||
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_FAILURE;
|
||||
res = GetFirstEditableChild(parent, &firstChild);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
*aOutIsFirst = (firstChild.get() == aNode);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast)
|
||||
{
|
||||
// check parms
|
||||
if (!aOutIsLast || !aNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// init out parms
|
||||
*aOutIsLast = PR_FALSE;
|
||||
|
||||
// find last editable child and compare it to aNode
|
||||
nsCOMPtr<nsIDOMNode> parent, lastChild;
|
||||
nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!parent) return NS_ERROR_FAILURE;
|
||||
res = GetLastEditableChild(parent, &lastChild);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
*aOutIsLast = (lastChild.get() == aNode);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild)
|
||||
{
|
||||
// check parms
|
||||
if (!aOutFirstChild || !aNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// init out parms
|
||||
*aOutFirstChild = nsnull;
|
||||
|
||||
// find first editable child
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
nsresult res = aNode->GetFirstChild(getter_AddRefs(child));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
while (child && !mEditor->IsEditable(child))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> tmp;
|
||||
res = child->GetNextSibling(getter_AddRefs(tmp));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!tmp) return NS_ERROR_FAILURE;
|
||||
child = tmp;
|
||||
}
|
||||
|
||||
*aOutFirstChild = child;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild)
|
||||
{
|
||||
// check parms
|
||||
if (!aOutLastChild || !aNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// init out parms
|
||||
*aOutLastChild = nsnull;
|
||||
|
||||
// find last editable child
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
nsresult res = aNode->GetLastChild(getter_AddRefs(child));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
while (child && !mEditor->IsEditable(child))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> tmp;
|
||||
res = child->GetPreviousSibling(getter_AddRefs(tmp));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!tmp) return NS_ERROR_FAILURE;
|
||||
child = tmp;
|
||||
}
|
||||
|
||||
*aOutLastChild = child;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// CreateMozBR: put a BR node with moz attribute at {aNode, aOffset}
|
||||
//
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include "nsIDOMNode.h"
|
||||
|
||||
#include "nsEditRules.h"
|
||||
#include "TypeInState.h"
|
||||
|
||||
/** Object that encapsulates HTML text-specific editing rules.
|
||||
*
|
||||
|
@ -94,11 +93,9 @@ protected:
|
|||
PRBool *aHandled,
|
||||
const nsString *inString,
|
||||
nsString *outString,
|
||||
TypeInState typeInState,
|
||||
PRInt32 aMaxLength);
|
||||
nsresult DidInsertText(nsIDOMSelection *aSelection, nsresult aResult);
|
||||
nsresult GetTopEnclosingPre(nsIDOMNode *aNode, nsIDOMNode** aOutPreNode);
|
||||
nsresult CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInState &aTypeInState);
|
||||
|
||||
nsresult WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult DidInsertBreak(nsIDOMSelection *aSelection, nsresult aResult);
|
||||
|
@ -144,46 +141,6 @@ protected:
|
|||
|
||||
// helper functions
|
||||
|
||||
/** insert aNode into a new style node of type aTag.
|
||||
* aSelection is optional. If provided, aSelection is set to (aNode, 0)
|
||||
* if aNode was successfully placed in a new style node
|
||||
* @param aNewStyleNode [OUT] The newly created style node, if result is successful
|
||||
* undefined if result is a failure.
|
||||
*/
|
||||
nsresult InsertStyleNode(nsIDOMNode *aNode,
|
||||
nsIAtom *aTag,
|
||||
nsIDOMSelection *aSelection,
|
||||
nsIDOMNode **aNewStyleNode);
|
||||
|
||||
/** inserts a new <FONT> node and sets the aAttr attribute to aValue */
|
||||
nsresult CreateFontStyleForInsertText(nsIDOMNode *aNewTextNode,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue,
|
||||
nsIDOMSelection *aInOutSelection);
|
||||
|
||||
/** create a new style node of type aTag in aParentNode at aOffset,
|
||||
* and create a new text node in the new style node.
|
||||
*
|
||||
* @param aParentNode the node that will be the parent of the new style node
|
||||
* @param aOffset the positoin in aParentNode to put the new style node
|
||||
* @param aTag the type of style node to create
|
||||
* no validation of aTag is done, caller is responsible
|
||||
* for passing in a reasonable tag name
|
||||
* @param aAttr optional attribute to set on new style node
|
||||
* ignored if it is an empty string
|
||||
* @param aValue optional value for aAttr. Ignored if aAttr is an empty string
|
||||
* @param aInOutSelection optional. If provided and if it is collapsed to a text node,
|
||||
* we use the text node and wrap a style node around it.
|
||||
* If provided, aSelection is collapsed to (newTextNode, 0)
|
||||
* if newTextNode was successfully created.
|
||||
*/
|
||||
nsresult InsertStyleAndNewTextNode(nsIDOMNode *aParentNode,
|
||||
PRInt32 aOffset,
|
||||
nsIAtom *aTag,
|
||||
const nsString &aAttr,
|
||||
const nsString &aValue,
|
||||
nsIDOMSelection *aSelection);
|
||||
|
||||
/** replaces newllines with breaks, if needed. acts on doc portion in aRange */
|
||||
nsresult ReplaceNewlines(nsIDOMRange *aRange);
|
||||
|
||||
|
@ -201,26 +158,6 @@ protected:
|
|||
insertion text to '*'s */
|
||||
nsresult EchoInsertionToPWBuff(PRInt32 aStart, PRInt32 aEnd, nsString *aOutString);
|
||||
|
||||
/** do the actual text insertion */
|
||||
nsresult DoTextInsertion(nsIDOMSelection *aSelection,
|
||||
PRBool *aCancel,
|
||||
const nsString *aInString,
|
||||
TypeInState aTypeInState);
|
||||
|
||||
nsresult GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetPriorHTMLSibling(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetNextHTMLSibling(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
|
||||
nsresult IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst);
|
||||
nsresult IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast);
|
||||
nsresult GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild);
|
||||
nsresult GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild);
|
||||
|
||||
nsresult CreateMozBR(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outBRNode);
|
||||
|
||||
|
||||
|
@ -248,7 +185,6 @@ class nsTextRulesInfo : public nsRulesInfo
|
|||
inString(0),
|
||||
outString(0),
|
||||
outputFormat(0),
|
||||
typeInState(),
|
||||
maxLength(-1),
|
||||
collapsedAction(nsIEditor::eNext),
|
||||
bOrdered(PR_FALSE),
|
||||
|
@ -263,7 +199,6 @@ class nsTextRulesInfo : public nsRulesInfo
|
|||
const nsString *inString;
|
||||
nsString *outString;
|
||||
const nsString *outputFormat;
|
||||
TypeInState typeInState;
|
||||
PRInt32 maxLength;
|
||||
|
||||
// kDeleteSelection
|
||||
|
|
|
@ -384,14 +384,6 @@ public:
|
|||
*/
|
||||
NS_IMETHOD DeleteNode(nsIDOMNode * aChild)=0;
|
||||
|
||||
/**
|
||||
* InsertNoneditableTextNode() inserts a noneditable text node, e.g. for formatting.
|
||||
* @param aParent The parent of the newly created node
|
||||
* @param aOffset The offset in the parent for the new node
|
||||
* @param aStr The string contents to be placed in the node
|
||||
*/
|
||||
NS_IMETHOD InsertNoneditableTextNode(nsIDOMNode* aParent, PRInt32 aOffset,
|
||||
nsString& aStr) = 0;
|
||||
/**
|
||||
* InsertFormattingForNode() sets a special dirty attribute on the node.
|
||||
* Usually this will be called immediately after creating a new node.
|
||||
|
|
Загрузка…
Ссылка в новой задаче