making editor hip to inline style changes on collapsed selections. plus lots of removal of unused code.

This commit is contained in:
jfrancis%netscape.com 2000-03-29 12:53:23 +00:00
Родитель 3ff6fe1c16
Коммит af4644e7c8
21 изменённых файлов: 2254 добавлений и 8688 удалений

Просмотреть файл

@ -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.