Fix for bug #46396: select after input confuses session history

Moved code that set initial value of text control via the editor from
CreateAnonymousContent() to a new method called SetInitialValue().
SetInitialValue() is now called during the frame's first reflow.
Added mUseEditor to indicate when it is safe to use the editor
to get and set values.
r=mjudge@netscape.com
This commit is contained in:
kin%netscape.com 2000-09-07 19:11:23 +00:00
Родитель 63ce73fabf
Коммит d48eb6681d
2 изменённых файлов: 116 добавлений и 68 удалений

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

@ -1063,6 +1063,7 @@ nsGfxTextControlFrame2::QueryInterface(const nsIID& aIID, void** aInstancePtr)
nsGfxTextControlFrame2::nsGfxTextControlFrame2(nsIPresShell* aShell):nsStackFrame(aShell)
{
mUseEditor=PR_FALSE;
mIsProcessing=PR_FALSE;
mNotifyOnInput = PR_FALSE;
mFormFrame = nsnull;
@ -1532,6 +1533,107 @@ nsGfxTextControlFrame2::CreateFrameFor(nsIPresContext* aPresContext,
return NS_ERROR_FAILURE;
}
nsresult
nsGfxTextControlFrame2::SetInitialValue()
{
// This method must be called during/after the text
// control frame's initial reflow to avoid any unintened
// forced reflows that might result when the editor
// calls into DOM/layout code while trying to set the
// initial string.
//
// This code used to be called from CreateAnonymousContent(),
// but when the editor set the initial string, it would trigger
// a PresShell listener which called FlushPendingNotifications()
// during frame construction. This was causing other form controls
// to display wrong values.
if (!mEditor)
return NS_ERROR_NOT_INITIALIZED;
// Check if this method has been called already.
// If so, just return early.
if (mUseEditor)
return NS_OK;
// Get the default value for the textfield.
nsAutoString defaultValue;
nsresult rv = NS_OK;
if (mCachedState)
defaultValue = mCachedState->GetUnicode();
else
rv = GetText(&defaultValue, PR_TRUE);
if (NS_FAILED(rv))
return rv;
// If we have a default value, insert it under the div we created
// above, but be sure to use the editor so that '*' characters get
// displayed for password fields, etc. SetTextControlFrameState()
// will call the editor for us.
mUseEditor = PR_TRUE;
if (defaultValue.Length() > 0)
{
PRUint32 editorFlags = 0;
rv = mEditor->GetFlags(&editorFlags);
if (NS_FAILED(rv))
return rv;
// Avoid causing reentrant painting and reflowing by telling the editor
// that we don't want it to force immediate view refreshes or force
// immediate reflows during any editor calls.
rv = mEditor->SetFlags(editorFlags |
nsIHTMLEditor::eEditorDisableForcedUpdatesMask |
nsIHTMLEditor::eEditorDisableForcedReflowsMask);
if (NS_FAILED(rv))
return rv;
// Now call SetTextControlFrameState() which will make the
// neccessary editor calls to set the default value.
// Make sure to turn off undo before setting the default
// value, and turn it back on afterwards. This will make
// sure we can't undo past the default value.
rv = mEditor->EnableUndo(PR_FALSE);
if (NS_FAILED(rv))
return rv;
SetTextControlFrameState(defaultValue);
rv = mEditor->EnableUndo(PR_TRUE);
if (NS_FAILED(rv))
return rv;
// Now restore the original editor flags.
rv = mEditor->SetFlags(editorFlags);
if (NS_FAILED(rv))
return rv;
}
// Free mCachedState since we don't need it anymore!
if (mCachedState)
{
delete mCachedState;
mCachedState = nsnull;
}
return NS_OK;
}
#define DIV_STRING "-moz-user-focus: none; border: 0px !important; padding: 0px; margin:0px; "
#define DIV_STRING_SINGLELINE "-moz-user-focus: none; white-space : nowrap; overflow:auto; border: 0px !important; padding: 0px; margin:0px"
@ -1805,67 +1907,6 @@ nsGfxTextControlFrame2::CreateAnonymousContent(nsIPresContext* aPresContext,
rv = txMgr->AddListener(NS_STATIC_CAST(nsITransactionListener*, mTextListener));
if (NS_FAILED(rv)) return rv;
}
// Get the default value for the textfield.
nsAutoString defaultValue;
if (mCachedState)
defaultValue = mCachedState->GetUnicode();
else
rv = GetText(&defaultValue, PR_TRUE);
if (NS_FAILED(rv))
return rv;
// If we have a default value, insert it under the div we created
// above, but be sure to use the editor so that '*' characters get
// displayed for password fields, etc. SetTextControlFrameState()
// will call the editor for us.
if (defaultValue.Length() > 0)
{
rv = mEditor->GetFlags(&editorFlags);
if (NS_FAILED(rv))
return rv;
// Avoid causing reentrant painting and reflowing by telling the editor
// that we don't want it to force immediate view refreshes or force
// immediate reflows during any editor calls.
rv = mEditor->SetFlags(editorFlags |
nsIHTMLEditor::eEditorDisableForcedUpdatesMask |
nsIHTMLEditor::eEditorDisableForcedReflowsMask);
if (NS_FAILED(rv))
return rv;
// Now call SetTextControlFrameState() which will make the
// neccessary editor calls to set the default value.
// Make sure to turn off undo before setting the default
// value, and turn it back on afterwards. This will make
// sure we can't undo past the default value.
rv = mEditor->EnableUndo(PR_FALSE);
if (NS_FAILED(rv))
return rv;
SetTextControlFrameState(defaultValue);
rv = mEditor->EnableUndo(PR_TRUE);
if (NS_FAILED(rv))
return rv;
// Now restore the original editor flags.
rv = mEditor->SetFlags(editorFlags);
if (NS_FAILED(rv))
return rv;
}
if (mContent)
{
@ -1949,6 +1990,7 @@ nsGfxTextControlFrame2::Reflow(nsIPresContext* aPresContext,
// make sure the the form registers itself on the initial/first reflow
if (mState & NS_FRAME_FIRST_REFLOW) {
SetInitialValue();
nsFormControlFrame::RegUnRegAccessKey(aPresContext, NS_STATIC_CAST(nsIFrame*, this), PR_TRUE);
nsFormFrame::AddFormControlFrame(aPresContext, *NS_STATIC_CAST(nsIFrame*, this));
mNotifyOnInput = PR_TRUE;//its ok to notify now. all has been prepared.
@ -1998,13 +2040,15 @@ nsGfxTextControlFrame2::GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize)
nsSize styleSize(CSS_NOTSET,CSS_NOTSET);
nsFormControlFrame::GetStyleSize(aPresContext, *aReflowState, styleSize);
if (mState & NS_FRAME_FIRST_REFLOW)
mNotifyOnInput = PR_TRUE;//its ok to notify now. all has been prepared.
if (!aReflowState)
return NS_OK;
if (mState & NS_FRAME_FIRST_REFLOW)
{
SetInitialValue();
mNotifyOnInput = PR_TRUE;//its ok to notify now. all has been prepared.
}
nsCompatibility mode;
aPresContext->GetCompatibilityMode(&mode);
PRBool navQuirksMode = eCompatibility_NavQuirks == mode && nameSpaceID == kNameSpaceID_HTML;
@ -2873,7 +2917,7 @@ nsGfxTextControlFrame2::CallOnChange()
nsString *
nsGfxTextControlFrame2::GetCachedString()
{
if (!mCachedState && mEditor)
if (!mCachedState && mEditor && mUseEditor)
{
mCachedState = new nsString;
if (!mCachedState)
@ -2887,7 +2931,7 @@ void nsGfxTextControlFrame2::GetTextControlFrameState(nsAWritableString& aValue)
{
aValue.SetLength(0); // initialize out param
if (mEditor)
if (mEditor && mUseEditor)
{
PRUint32 flags = nsIDocumentEncoder::OutputLFLineBreak;;
@ -2908,6 +2952,8 @@ void nsGfxTextControlFrame2::GetTextControlFrameState(nsAWritableString& aValue)
mEditor->OutputToString(aValue, NS_LITERAL_STRING("text/plain"), flags);
}
else if (mCachedState && mCachedState->Length() > 0)
aValue.Assign(*mCachedState);
}
@ -2916,7 +2962,7 @@ void nsGfxTextControlFrame2::GetTextControlFrameState(nsAWritableString& aValue)
void
nsGfxTextControlFrame2::SetTextControlFrameState(const nsAReadableString& aValue)
{
if (mEditor)
if (mEditor && mUseEditor)
{
nsAutoString currentValue;
nsAutoString format; format.AssignWithConversion("text/plain");

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

@ -152,6 +152,7 @@ public: //for methods who access nsGfxTextControlFrame2 directly
NS_IMETHOD InternalContentChanged();//notify that we have some kind of change.
NS_IMETHOD CallOnChange();
protected:
nsresult SetInitialValue();
nsString *GetCachedString();
virtual PRIntn GetSkipSides() const;
void RemoveNewlines(nsString &aString);
@ -243,6 +244,7 @@ private:
nscoord mSuggestedHeight;
nsSize mSize;
PRPackedBool mUseEditor;
PRPackedBool mIsProcessing;
PRPackedBool mNotifyOnInput;//default this to off to stop any notifications until setup is complete