mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 534785 - Move the ownership of editor and selection controller from the text frame to the content node; r=roc,jst sr=roc
--HG-- rename : layout/reftests/forms/placeholder/placeholder-14.html => layout/reftests/forms/placeholder/placeholder-18.html
This commit is contained in:
parent
b9dde1111f
commit
844e62b830
@ -1615,6 +1615,14 @@ public:
|
||||
static already_AddRefed<mozilla::layers::LayerManager>
|
||||
LayerManagerForDocument(nsIDocument *aDoc);
|
||||
|
||||
/**
|
||||
* Determine whether a content node is focused or not,
|
||||
*
|
||||
* @param aContent the content node to check
|
||||
* @return true if the content node is focused, false otherwise.
|
||||
*/
|
||||
static PRBool IsFocusedContent(nsIContent *aContent);
|
||||
|
||||
private:
|
||||
|
||||
static PRBool InitializeEventTable();
|
||||
|
@ -178,6 +178,8 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsFrameManager.h"
|
||||
#include "BasicLayers.h"
|
||||
#include "nsFocusManager.h"
|
||||
#include "nsTextEditorState.h"
|
||||
|
||||
#ifdef IBMBIDI
|
||||
#include "nsIBidiKeyboard.h"
|
||||
@ -1047,6 +1049,8 @@ nsContentUtils::Shutdown()
|
||||
NS_IF_RELEASE(sSameOriginChecker);
|
||||
|
||||
nsAutoGCRoot::Shutdown();
|
||||
|
||||
nsTextEditorState::ShutDown();
|
||||
}
|
||||
|
||||
// static
|
||||
@ -5953,6 +5957,15 @@ mozAutoRemovableBlockerRemover::~mozAutoRemovableBlockerRemover()
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
PRBool
|
||||
nsContentUtils::IsFocusedContent(nsIContent* aContent)
|
||||
{
|
||||
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
|
||||
return fm && fm->GetFocusedContent() == aContent;
|
||||
}
|
||||
|
||||
void nsContentUtils::RemoveNewlines(nsString &aString)
|
||||
{
|
||||
// strip CR/LF and null
|
||||
|
@ -40,32 +40,174 @@
|
||||
#define nsITextControlElement_h___
|
||||
|
||||
#include "nsISupports.h"
|
||||
class nsIContent;
|
||||
class nsAString;
|
||||
class nsITextControlFrame;
|
||||
class nsIEditor;
|
||||
class nsISelectionController;
|
||||
class nsFrameSelection;
|
||||
class nsTextControlFrame;
|
||||
|
||||
// IID for the nsITextControl interface
|
||||
#define NS_ITEXTCONTROLELEMENT_IID \
|
||||
{ 0x8c22af1e, 0x1dd2, 0x11b2, \
|
||||
{ 0x9d, 0x72, 0xb4, 0xc1, 0x53, 0x68, 0xdc, 0xa1 } }
|
||||
{ 0x66545dde, 0x3f4a, 0x49fd, \
|
||||
{ 0x82, 0x73, 0x69, 0x7e, 0xab, 0x54, 0x06, 0x0a } }
|
||||
|
||||
/**
|
||||
* This interface is used for the text control frame to store its value away
|
||||
* into the content.
|
||||
* This interface is used for the text control frame to get the editor and
|
||||
* selection controller objects, and some helper properties.
|
||||
*/
|
||||
class nsITextControlElement : public nsISupports {
|
||||
public:
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ITEXTCONTROLELEMENT_IID)
|
||||
|
||||
/**
|
||||
* Set the control's value without security checks
|
||||
*/
|
||||
NS_IMETHOD TakeTextFrameValue(const nsAString& aValue) = 0;
|
||||
|
||||
/**
|
||||
* Tell the control that value has been deliberately changed (or not).
|
||||
*/
|
||||
NS_IMETHOD SetValueChanged(PRBool changed) = 0;
|
||||
|
||||
/**
|
||||
* Find out whether this is a single line text control. (text or password)
|
||||
* @return whether this is a single line text control
|
||||
*/
|
||||
NS_IMETHOD_(PRBool) IsSingleLineTextControl() const = 0;
|
||||
|
||||
/**
|
||||
* Find out whether this control is a textarea.
|
||||
* @return whether this is a textarea text control
|
||||
*/
|
||||
NS_IMETHOD_(PRBool) IsTextArea() const = 0;
|
||||
|
||||
/**
|
||||
* Find out whether this control edits plain text. (Currently always true.)
|
||||
* @return whether this is a plain text control
|
||||
*/
|
||||
NS_IMETHOD_(PRBool) IsPlainTextControl() const = 0;
|
||||
|
||||
/**
|
||||
* Find out whether this is a password control (input type=password)
|
||||
* @return whether this is a password ontrol
|
||||
*/
|
||||
NS_IMETHOD_(PRBool) IsPasswordTextControl() const = 0;
|
||||
|
||||
/**
|
||||
* Get the cols attribute (if textarea) or a default
|
||||
* @return the number of columns to use
|
||||
*/
|
||||
NS_IMETHOD_(PRInt32) GetCols() = 0;
|
||||
|
||||
/**
|
||||
* Get the column index to wrap at, or -1 if we shouldn't wrap
|
||||
*/
|
||||
NS_IMETHOD_(PRInt32) GetWrapCols() = 0;
|
||||
|
||||
/**
|
||||
* Get the rows attribute (if textarea) or a default
|
||||
* @return the number of rows to use
|
||||
*/
|
||||
NS_IMETHOD_(PRInt32) GetRows() = 0;
|
||||
|
||||
/**
|
||||
* Get the default value of the text control
|
||||
*/
|
||||
NS_IMETHOD_(void) GetDefaultValueFromContent(nsAString& aValue) = 0;
|
||||
|
||||
/**
|
||||
* Return true if the value of the control has been changed.
|
||||
*/
|
||||
NS_IMETHOD_(PRBool) ValueChanged() const = 0;
|
||||
|
||||
/**
|
||||
* Get the current value of the text editor.
|
||||
*
|
||||
* @param aValue the buffer to retrieve the value in
|
||||
* @param aIgnoreWrap whether to ignore the text wrapping behavior specified
|
||||
* for the element.
|
||||
*/
|
||||
NS_IMETHOD_(void) GetTextEditorValue(nsAString& aValue, PRBool aIgnoreWrap) const = 0;
|
||||
|
||||
/**
|
||||
* Set the current value of the text editor.
|
||||
*
|
||||
* @param aValue the new value for the text control.
|
||||
* @param aUserInput whether this value is coming from user input.
|
||||
*/
|
||||
NS_IMETHOD_(void) SetTextEditorValue(const nsAString& aValue, PRBool aUserInput) = 0;
|
||||
|
||||
/**
|
||||
* Get the editor object associated with the text editor.
|
||||
* The return value is null if the control does not support an editor
|
||||
* (for example, if it is a checkbox.)
|
||||
*/
|
||||
NS_IMETHOD_(nsIEditor*) GetTextEditor() = 0;
|
||||
|
||||
/**
|
||||
* Get the selection controller object associated with the text editor.
|
||||
* The return value is null if the control does not support an editor
|
||||
* (for example, if it is a checkbox.)
|
||||
*/
|
||||
NS_IMETHOD_(nsISelectionController*) GetSelectionController() = 0;
|
||||
|
||||
NS_IMETHOD_(nsFrameSelection*) GetConstFrameSelection() = 0;
|
||||
|
||||
/**
|
||||
* Binds a frame to the text control. This is performed when a frame
|
||||
* is created for the content node.
|
||||
*/
|
||||
NS_IMETHOD BindToFrame(nsTextControlFrame* aFrame) = 0;
|
||||
|
||||
/**
|
||||
* Unbinds a frame from the text control. This is performed when a frame
|
||||
* belonging to a content node is destroyed.
|
||||
*/
|
||||
NS_IMETHOD_(void) UnbindFromFrame(nsTextControlFrame* aFrame) = 0;
|
||||
|
||||
/**
|
||||
* Creates an editor for the text control. This should happen when
|
||||
* a frame has been created for the text control element, but the created
|
||||
* editor may outlive the frame itself.
|
||||
*/
|
||||
NS_IMETHOD CreateEditor() = 0;
|
||||
|
||||
/**
|
||||
* Get the anonymous root node for the text control.
|
||||
*/
|
||||
NS_IMETHOD_(nsIContent*) GetRootEditorNode() = 0;
|
||||
|
||||
/**
|
||||
* Get the placeholder anonymous node for the text control.
|
||||
*/
|
||||
NS_IMETHOD_(nsIContent*) GetPlaceholderNode() = 0;
|
||||
|
||||
/**
|
||||
* Initialize the keyboard event listeners.
|
||||
*/
|
||||
NS_IMETHOD_(void) InitializeKeyboardEventListeners() = 0;
|
||||
|
||||
/**
|
||||
* Notify the text control that the placeholder text needs to be updated.
|
||||
*/
|
||||
NS_IMETHOD_(void) UpdatePlaceholderText(PRBool aNotify) = 0;
|
||||
|
||||
/**
|
||||
* Show/hide the placeholder for the control.
|
||||
*/
|
||||
NS_IMETHOD_(void) SetPlaceholderClass(PRBool aVisible, PRBool aNotify) = 0;
|
||||
|
||||
static const PRInt32 DEFAULT_COLS = 20;
|
||||
static const PRInt32 DEFAULT_ROWS = 1;
|
||||
static const PRInt32 DEFAULT_ROWS_TEXTAREA = 2;
|
||||
static const PRInt32 DEFAULT_UNDO_CAP = 1000;
|
||||
|
||||
// wrap can be one of these three values.
|
||||
typedef enum {
|
||||
eHTMLTextWrap_Off = 1, // "off"
|
||||
eHTMLTextWrap_Hard = 2, // "hard"
|
||||
eHTMLTextWrap_Soft = 3 // the default
|
||||
} nsHTMLTextWrap;
|
||||
|
||||
static PRBool
|
||||
GetWrapPropertyEnum(nsIContent* aContent, nsHTMLTextWrap& aWrapProp);
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsITextControlElement,
|
||||
|
@ -58,6 +58,7 @@ CPPSRCS = \
|
||||
nsGenericHTMLElement.cpp \
|
||||
nsFormSubmission.cpp \
|
||||
nsImageMapUtils.cpp \
|
||||
nsTextEditorState.cpp \
|
||||
nsHTMLAnchorElement.cpp \
|
||||
nsHTMLAreaElement.cpp \
|
||||
nsHTMLBRElement.cpp \
|
||||
@ -124,6 +125,7 @@ INCLUDES += \
|
||||
-I$(srcdir)/../../../base/src \
|
||||
-I$(srcdir)/../../../events/src \
|
||||
-I$(srcdir)/../../../xbl/src \
|
||||
-I$(srcdir)/../../../../layout/forms \
|
||||
-I$(srcdir)/../../../../layout/style \
|
||||
-I$(srcdir)/../../../../layout/tables \
|
||||
-I$(srcdir)/../../../../layout/xul/base/src \
|
||||
|
@ -110,6 +110,7 @@
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
#include "mozAutoDocUpdate.h"
|
||||
#include "nsHtml5Module.h"
|
||||
#include "nsITextControlElement.h"
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
@ -2707,14 +2708,20 @@ nsGenericHTMLFormElement::IsTextControl(PRBool aExcludePassword) const
|
||||
type == NS_FORM_TEXTAREA;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsGenericHTMLFormElement::IsSingleLineTextControlInternal(PRBool aExcludePassword,
|
||||
PRInt32 aType) const
|
||||
{
|
||||
return aType == NS_FORM_INPUT_TEXT ||
|
||||
aType == NS_FORM_INPUT_SEARCH ||
|
||||
aType == NS_FORM_INPUT_TEL ||
|
||||
(!aExcludePassword && aType == NS_FORM_INPUT_PASSWORD);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsGenericHTMLFormElement::IsSingleLineTextControl(PRBool aExcludePassword) const
|
||||
{
|
||||
PRInt32 type = GetType();
|
||||
return type == NS_FORM_INPUT_TEXT ||
|
||||
type == NS_FORM_INPUT_SEARCH ||
|
||||
type == NS_FORM_INPUT_TEL ||
|
||||
(!aExcludePassword && type == NS_FORM_INPUT_PASSWORD);
|
||||
return IsSingleLineTextControlInternal(aExcludePassword, GetType());
|
||||
}
|
||||
|
||||
PRBool
|
||||
@ -3166,12 +3173,10 @@ nsGenericHTMLElement::GetEditorInternal(nsIEditor** aEditor)
|
||||
{
|
||||
*aEditor = nsnull;
|
||||
|
||||
nsIFormControlFrame *fcFrame = GetFormControlFrame(PR_FALSE);
|
||||
if (fcFrame) {
|
||||
nsITextControlFrame *textFrame = do_QueryFrame(fcFrame);
|
||||
if (textFrame) {
|
||||
return textFrame->GetEditor(aEditor);
|
||||
}
|
||||
nsCOMPtr<nsITextControlElement> textCtrl = do_QueryInterface(this);
|
||||
if (textCtrl) {
|
||||
*aEditor = textCtrl->GetTextEditor();
|
||||
NS_IF_ADDREF(*aEditor);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -863,6 +863,8 @@ protected:
|
||||
|
||||
void UpdateEditableFormControlState();
|
||||
|
||||
PRBool IsSingleLineTextControlInternal(PRBool aExcludePassword, PRInt32 mType) const;
|
||||
|
||||
// The focusability state of this form control. eUnfocusable means that it
|
||||
// shouldn't be focused at all, eInactiveWindow means it's in an inactive
|
||||
// window, eActiveWindow means it's in an active window.
|
||||
|
@ -112,6 +112,8 @@
|
||||
|
||||
#include "nsTextEditRules.h"
|
||||
|
||||
#include "nsTextEditorState.h"
|
||||
|
||||
// XXX align=left, hspace, vspace, border? other nav4 attrs
|
||||
|
||||
static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
|
||||
@ -308,8 +310,29 @@ public:
|
||||
virtual PRInt32 IntrinsicState() const;
|
||||
|
||||
// nsITextControlElement
|
||||
NS_IMETHOD TakeTextFrameValue(const nsAString& aValue);
|
||||
NS_IMETHOD SetValueChanged(PRBool aValueChanged);
|
||||
NS_IMETHOD_(PRBool) IsSingleLineTextControl() const;
|
||||
NS_IMETHOD_(PRBool) IsTextArea() const;
|
||||
NS_IMETHOD_(PRBool) IsPlainTextControl() const;
|
||||
NS_IMETHOD_(PRBool) IsPasswordTextControl() const;
|
||||
NS_IMETHOD_(PRInt32) GetCols();
|
||||
NS_IMETHOD_(PRInt32) GetWrapCols();
|
||||
NS_IMETHOD_(PRInt32) GetRows();
|
||||
NS_IMETHOD_(void) GetDefaultValueFromContent(nsAString& aValue);
|
||||
NS_IMETHOD_(PRBool) ValueChanged() const;
|
||||
NS_IMETHOD_(void) GetTextEditorValue(nsAString& aValue, PRBool aIgnoreWrap) const;
|
||||
NS_IMETHOD_(void) SetTextEditorValue(const nsAString& aValue, PRBool aUserInput);
|
||||
NS_IMETHOD_(nsIEditor*) GetTextEditor();
|
||||
NS_IMETHOD_(nsISelectionController*) GetSelectionController();
|
||||
NS_IMETHOD_(nsFrameSelection*) GetConstFrameSelection();
|
||||
NS_IMETHOD BindToFrame(nsTextControlFrame* aFrame);
|
||||
NS_IMETHOD_(void) UnbindFromFrame(nsTextControlFrame* aFrame);
|
||||
NS_IMETHOD CreateEditor();
|
||||
NS_IMETHOD_(nsIContent*) GetRootEditorNode();
|
||||
NS_IMETHOD_(nsIContent*) GetPlaceholderNode();
|
||||
NS_IMETHOD_(void) UpdatePlaceholderText(PRBool aNotify);
|
||||
NS_IMETHOD_(void) SetPlaceholderClass(PRBool aVisible, PRBool aNotify);
|
||||
NS_IMETHOD_(void) InitializeKeyboardEventListeners();
|
||||
|
||||
// nsIFileControlElement
|
||||
virtual void GetDisplayFileName(nsAString& aFileName);
|
||||
@ -341,9 +364,12 @@ public:
|
||||
|
||||
void MaybeLoadImage();
|
||||
protected:
|
||||
// Pull IsSingleLineTextControl into our scope, otherwise it'd be hidden
|
||||
// by the nsITextControlElement version.
|
||||
using nsGenericHTMLFormElement::IsSingleLineTextControl;
|
||||
|
||||
// Helper method
|
||||
nsresult SetValueInternal(const nsAString& aValue,
|
||||
nsITextControlFrame* aFrame,
|
||||
PRBool aUserInput);
|
||||
|
||||
void ClearFileNames() {
|
||||
@ -455,6 +481,9 @@ protected:
|
||||
*/
|
||||
PRBool NeedToInitializeEditorForEvent(nsEventChainPreVisitor& aVisitor) const;
|
||||
|
||||
void FreeData();
|
||||
nsTextEditorState *GetEditorState() const;
|
||||
|
||||
nsCOMPtr<nsIControllers> mControllers;
|
||||
|
||||
/**
|
||||
@ -467,10 +496,24 @@ protected:
|
||||
* @see GET_BOOLBIT / SET_BOOLBIT macros and BF_* field identifiers
|
||||
*/
|
||||
PRInt16 mBitField;
|
||||
/*
|
||||
* In mInputData, the mState field is used if IsSingleLineTextControl returns
|
||||
* true and mValue is used otherwise. We have to be careful when handling it
|
||||
* on a type change.
|
||||
*
|
||||
* Accessing the mState member should be done using the GetEditorState function,
|
||||
* which returns null if the state is not present.
|
||||
*/
|
||||
union InputData {
|
||||
/**
|
||||
* The current value of the input if it has been changed from the default
|
||||
*/
|
||||
char* mValue;
|
||||
/**
|
||||
* The state of the text editor associated with the text/password input
|
||||
*/
|
||||
nsTextEditorState* mState;
|
||||
} mInputData;
|
||||
/**
|
||||
* The value of the input if it is a file input. This is the list of filenames
|
||||
* used when uploading a file. It is vital that this is kept separate from
|
||||
@ -503,20 +546,43 @@ nsHTMLInputElement::nsHTMLInputElement(nsINodeInfo *aNodeInfo,
|
||||
PRBool aFromParser)
|
||||
: nsGenericHTMLFormElement(aNodeInfo),
|
||||
mType(kInputDefaultType->value),
|
||||
mBitField(0),
|
||||
mValue(nsnull)
|
||||
mBitField(0)
|
||||
{
|
||||
SET_BOOLBIT(mBitField, BF_PARSER_CREATING, aFromParser);
|
||||
mInputData.mState = new nsTextEditorState(this);
|
||||
NS_ADDREF(mInputData.mState);
|
||||
}
|
||||
|
||||
nsHTMLInputElement::~nsHTMLInputElement()
|
||||
{
|
||||
DestroyImageLoadingContent();
|
||||
if (mValue) {
|
||||
nsMemory::Free(mValue);
|
||||
FreeData();
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLInputElement::FreeData()
|
||||
{
|
||||
if (!IsSingleLineTextControl(PR_FALSE)) {
|
||||
nsMemory::Free(mInputData.mValue);
|
||||
mInputData.mValue = nsnull;
|
||||
} else {
|
||||
NS_IF_RELEASE(mInputData.mState);
|
||||
}
|
||||
}
|
||||
|
||||
nsTextEditorState*
|
||||
nsHTMLInputElement::GetEditorState() const
|
||||
{
|
||||
if (!IsSingleLineTextControl(PR_FALSE)) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
NS_ASSERTION(mInputData.mState,
|
||||
"Single line text controls need to have a state associated with them");
|
||||
|
||||
return mInputData.mState;
|
||||
}
|
||||
|
||||
|
||||
// nsISupports
|
||||
|
||||
@ -524,6 +590,9 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLInputElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLInputElement,
|
||||
nsGenericHTMLFormElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mControllers)
|
||||
if (tmp->IsSingleLineTextControl(PR_FALSE)) {
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mInputData.mState, nsTextEditorState)
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsHTMLInputElement, nsGenericElement)
|
||||
@ -578,7 +647,7 @@ nsHTMLInputElement::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
|
||||
nsAutoString value;
|
||||
const_cast<nsHTMLInputElement*>(this)->GetValue(value);
|
||||
// SetValueInternal handles setting the VALUE_CHANGED bit for us
|
||||
it->SetValueInternal(value, nsnull, PR_FALSE);
|
||||
it->SetValueInternal(value, PR_FALSE);
|
||||
}
|
||||
break;
|
||||
case NS_FORM_INPUT_FILE:
|
||||
@ -707,20 +776,17 @@ nsHTMLInputElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
||||
mType = kInputDefaultType->value;
|
||||
}
|
||||
|
||||
// If we are changing type from File/Text/Tel/Passwd
|
||||
// to other input types we need save the mValue into value attribute
|
||||
if (mValue &&
|
||||
// If we are changing type from File/Text/Tel/Passwd to other input types
|
||||
// we need save the mValue into value attribute
|
||||
if (mInputData.mValue &&
|
||||
mType != NS_FORM_INPUT_TEXT &&
|
||||
mType != NS_FORM_INPUT_SEARCH &&
|
||||
mType != NS_FORM_INPUT_PASSWORD &&
|
||||
mType != NS_FORM_INPUT_TEL &&
|
||||
mType != NS_FORM_INPUT_FILE) {
|
||||
SetAttr(kNameSpaceID_None, nsGkAtoms::value,
|
||||
NS_ConvertUTF8toUTF16(mValue), PR_FALSE);
|
||||
if (mValue) {
|
||||
nsMemory::Free(mValue);
|
||||
mValue = nsnull;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16(mInputData.mValue), PR_FALSE);
|
||||
FreeData();
|
||||
}
|
||||
|
||||
if (mType != NS_FORM_INPUT_IMAGE) {
|
||||
@ -889,40 +955,9 @@ nsHTMLInputElement::SetSize(PRUint32 aValue)
|
||||
NS_IMETHODIMP
|
||||
nsHTMLInputElement::GetValue(nsAString& aValue)
|
||||
{
|
||||
if (IsSingleLineTextControl(PR_FALSE)) {
|
||||
// No need to flush here, if there's no frame created for this
|
||||
// input yet, there won't be a value in it (that we don't already
|
||||
// have) even if we force it to be created
|
||||
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
|
||||
|
||||
PRBool frameOwnsValue = PR_FALSE;
|
||||
if (formControlFrame) {
|
||||
nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
|
||||
if (textControlFrame) {
|
||||
textControlFrame->OwnsValue(&frameOwnsValue);
|
||||
} else {
|
||||
// We assume if it's not a text control frame that it owns the value
|
||||
frameOwnsValue = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (frameOwnsValue) {
|
||||
formControlFrame->GetFormProperty(nsGkAtoms::value, aValue);
|
||||
} else {
|
||||
if (!GET_BOOLBIT(mBitField, BF_VALUE_CHANGED) || !mValue) {
|
||||
GetDefaultValue(aValue);
|
||||
} else {
|
||||
CopyUTF8toUTF16(mValue, aValue);
|
||||
}
|
||||
|
||||
// If the value is not owned by the frame, then we should handle any
|
||||
// exiting newline characters inside it, instead of relying on the
|
||||
// editor to do it for us.
|
||||
nsString value(aValue);
|
||||
nsTextEditRules::HandleNewLines(value, -1);
|
||||
aValue.Assign(value);
|
||||
}
|
||||
|
||||
nsTextEditorState* state = GetEditorState();
|
||||
if (state) {
|
||||
state->GetValue(aValue, PR_TRUE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -979,7 +1014,7 @@ nsHTMLInputElement::SetValue(const nsAString& aValue)
|
||||
}
|
||||
}
|
||||
else {
|
||||
SetValueInternal(aValue, nsnull, PR_FALSE);
|
||||
SetValueInternal(aValue, PR_FALSE);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -1045,21 +1080,99 @@ nsHTMLInputElement::SetUserInput(const nsAString& aValue)
|
||||
{
|
||||
SetSingleFileName(aValue);
|
||||
} else {
|
||||
SetValueInternal(aValue, nsnull, PR_TRUE);
|
||||
SetValueInternal(aValue, PR_TRUE);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLInputElement::TakeTextFrameValue(const nsAString& aValue)
|
||||
NS_IMETHODIMP_(nsIEditor*)
|
||||
nsHTMLInputElement::GetTextEditor()
|
||||
{
|
||||
if (mValue) {
|
||||
nsMemory::Free(mValue);
|
||||
nsTextEditorState *state = GetEditorState();
|
||||
if (state) {
|
||||
return state->GetEditor();
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsISelectionController*)
|
||||
nsHTMLInputElement::GetSelectionController()
|
||||
{
|
||||
nsTextEditorState *state = GetEditorState();
|
||||
if (state) {
|
||||
return state->GetSelectionController();
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsFrameSelection*
|
||||
nsHTMLInputElement::GetConstFrameSelection()
|
||||
{
|
||||
nsTextEditorState *state = GetEditorState();
|
||||
if (state) {
|
||||
return state->GetConstFrameSelection();
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLInputElement::BindToFrame(nsTextControlFrame* aFrame)
|
||||
{
|
||||
nsTextEditorState *state = GetEditorState();
|
||||
if (state) {
|
||||
return state->BindToFrame(aFrame);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsHTMLInputElement::UnbindFromFrame(nsTextControlFrame* aFrame)
|
||||
{
|
||||
nsTextEditorState *state = GetEditorState();
|
||||
if (state) {
|
||||
state->UnbindFromFrame(aFrame);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLInputElement::CreateEditor()
|
||||
{
|
||||
nsTextEditorState *state = GetEditorState();
|
||||
if (state) {
|
||||
return state->PrepareEditor();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsIContent*)
|
||||
nsHTMLInputElement::GetRootEditorNode()
|
||||
{
|
||||
nsTextEditorState *state = GetEditorState();
|
||||
if (state) {
|
||||
return state->GetRootNode();
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsIContent*)
|
||||
nsHTMLInputElement::GetPlaceholderNode()
|
||||
{
|
||||
nsTextEditorState *state = GetEditorState();
|
||||
if (state) {
|
||||
return state->GetPlaceholderNode();
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsHTMLInputElement::UpdatePlaceholderText(PRBool aNotify)
|
||||
{
|
||||
nsTextEditorState *state = GetEditorState();
|
||||
if (state) {
|
||||
state->UpdatePlaceholderText(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsHTMLInputElement::SetPlaceholderClass(PRBool aVisible, PRBool aNotify)
|
||||
{
|
||||
nsTextEditorState *state = GetEditorState();
|
||||
if (state) {
|
||||
state->SetPlaceholderClass(aVisible, aNotify);
|
||||
}
|
||||
nsString value(aValue);
|
||||
nsContentUtils::PlatformToDOMLineBreaks(value);
|
||||
mValue = ToNewUTF8String(value);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1158,32 +1271,19 @@ nsHTMLInputElement::UpdateFileList()
|
||||
|
||||
nsresult
|
||||
nsHTMLInputElement::SetValueInternal(const nsAString& aValue,
|
||||
nsITextControlFrame* aFrame,
|
||||
PRBool aUserInput)
|
||||
{
|
||||
NS_PRECONDITION(mType != NS_FORM_INPUT_FILE,
|
||||
"Don't call SetValueInternal for file inputs");
|
||||
|
||||
if (IsSingleLineTextControl(PR_FALSE)) {
|
||||
nsIFormControlFrame* formControlFrame = aFrame;
|
||||
if (!formControlFrame) {
|
||||
// No need to flush here, if there's no frame at this point we
|
||||
// don't need to force creation of one just to tell it about this
|
||||
// new value.
|
||||
formControlFrame = GetFormControlFrame(PR_FALSE);
|
||||
}
|
||||
|
||||
if (formControlFrame) {
|
||||
// Always set the value in the frame. If the frame does not own the
|
||||
// value yet (per OwnsValue()), it will turn around and call
|
||||
// TakeTextFrameValue() on us, but will update its display with the new
|
||||
// value if needed.
|
||||
return formControlFrame->SetFormProperty(
|
||||
aUserInput ? nsGkAtoms::userInput : nsGkAtoms::value, aValue);
|
||||
}
|
||||
|
||||
// Need to set the value changed flag here, so that
|
||||
// nsTextControlFrame::UpdateValueDisplay retrieves the correct value
|
||||
// if needed.
|
||||
SetValueChanged(PR_TRUE);
|
||||
return TakeTextFrameValue(aValue);
|
||||
mInputData.mState->SetValue(aValue, aUserInput);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mType == NS_FORM_INPUT_FILE) {
|
||||
@ -1210,9 +1310,8 @@ nsHTMLInputElement::SetValueChanged(PRBool aValueChanged)
|
||||
{
|
||||
SET_BOOLBIT(mBitField, BF_VALUE_CHANGED, aValueChanged);
|
||||
if (!aValueChanged) {
|
||||
if (mValue) {
|
||||
nsMemory::Free(mValue);
|
||||
mValue = nsnull;
|
||||
if (!IsSingleLineTextControl(PR_FALSE)) {
|
||||
FreeData();
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
@ -2281,6 +2380,19 @@ nsHTMLInputElement::ParseAttribute(PRInt32 aNamespaceID,
|
||||
ClearFileNames();
|
||||
}
|
||||
|
||||
// Only single line text inputs have a text editor state.
|
||||
PRBool isNewTypeSingleLine =
|
||||
IsSingleLineTextControlInternal(PR_FALSE, newType);
|
||||
PRBool isCurrentTypeSingleLine =
|
||||
IsSingleLineTextControl(PR_FALSE);
|
||||
if (isNewTypeSingleLine && !isCurrentTypeSingleLine) {
|
||||
FreeData();
|
||||
mInputData.mState = new nsTextEditorState(this);
|
||||
NS_ADDREF(mInputData.mState);
|
||||
} else if (isCurrentTypeSingleLine && !isNewTypeSingleLine) {
|
||||
FreeData();
|
||||
}
|
||||
|
||||
mType = newType;
|
||||
}
|
||||
|
||||
@ -2909,7 +3021,7 @@ nsHTMLInputElement::RestoreState(nsPresState* aState)
|
||||
case NS_FORM_INPUT_TEL:
|
||||
case NS_FORM_INPUT_HIDDEN:
|
||||
{
|
||||
SetValueInternal(inputState->GetValue(), nsnull, PR_FALSE);
|
||||
SetValueInternal(inputState->GetValue(), PR_FALSE);
|
||||
break;
|
||||
}
|
||||
case NS_FORM_INPUT_FILE:
|
||||
@ -3286,3 +3398,98 @@ NS_GetRadioGetCheckedChangedVisitor(PRBool* aCheckedChanged,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsHTMLInputElement::IsSingleLineTextControl() const
|
||||
{
|
||||
return IsSingleLineTextControl(PR_FALSE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsHTMLInputElement::IsTextArea() const
|
||||
{
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsHTMLInputElement::IsPlainTextControl() const
|
||||
{
|
||||
// need to check our HTML attribute and/or CSS.
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsHTMLInputElement::IsPasswordTextControl() const
|
||||
{
|
||||
return mType == NS_FORM_INPUT_PASSWORD;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRInt32)
|
||||
nsHTMLInputElement::GetCols()
|
||||
{
|
||||
// Else we know (assume) it is an input with size attr
|
||||
const nsAttrValue* attr = GetParsedAttr(nsGkAtoms::size);
|
||||
if (attr && attr->Type() == nsAttrValue::eInteger) {
|
||||
PRInt32 cols = attr->GetIntegerValue();
|
||||
if (cols > 0) {
|
||||
return cols;
|
||||
}
|
||||
}
|
||||
|
||||
return DEFAULT_COLS;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRInt32)
|
||||
nsHTMLInputElement::GetWrapCols()
|
||||
{
|
||||
return -1; // only textarea's can have wrap cols
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRInt32)
|
||||
nsHTMLInputElement::GetRows()
|
||||
{
|
||||
return DEFAULT_ROWS;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsHTMLInputElement::GetDefaultValueFromContent(nsAString& aValue)
|
||||
{
|
||||
nsTextEditorState *state = GetEditorState();
|
||||
if (state) {
|
||||
GetDefaultValue(aValue);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsHTMLInputElement::ValueChanged() const
|
||||
{
|
||||
return GET_BOOLBIT(mBitField, BF_VALUE_CHANGED);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsHTMLInputElement::GetTextEditorValue(nsAString& aValue,
|
||||
PRBool aIgnoreWrap) const
|
||||
{
|
||||
nsTextEditorState *state = GetEditorState();
|
||||
if (state) {
|
||||
state->GetValue(aValue, aIgnoreWrap);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsHTMLInputElement::SetTextEditorValue(const nsAString& aValue,
|
||||
PRBool aUserInput)
|
||||
{
|
||||
nsTextEditorState *state = GetEditorState();
|
||||
if (state) {
|
||||
state->SetValue(aValue, aUserInput);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsHTMLInputElement::InitializeKeyboardEventListeners()
|
||||
{
|
||||
nsTextEditorState *state = GetEditorState();
|
||||
if (state) {
|
||||
state->InitializeKeyboardEventListeners();
|
||||
}
|
||||
}
|
||||
|
@ -77,6 +77,8 @@
|
||||
#include "mozAutoDocUpdate.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
|
||||
#include "nsTextEditorState.h"
|
||||
|
||||
static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
|
||||
|
||||
#define NS_NO_CONTENT_DISPATCH (1 << 0)
|
||||
@ -90,7 +92,6 @@ class nsHTMLTextAreaElement : public nsGenericHTMLFormElement,
|
||||
{
|
||||
public:
|
||||
nsHTMLTextAreaElement(nsINodeInfo *aNodeInfo, PRBool aFromParser = PR_FALSE);
|
||||
virtual ~nsHTMLTextAreaElement();
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
@ -126,8 +127,29 @@ public:
|
||||
virtual PRBool RestoreState(nsPresState* aState);
|
||||
|
||||
// nsITextControlElemet
|
||||
NS_IMETHOD TakeTextFrameValue(const nsAString& aValue);
|
||||
NS_IMETHOD SetValueChanged(PRBool aValueChanged);
|
||||
NS_IMETHOD_(PRBool) IsSingleLineTextControl() const;
|
||||
NS_IMETHOD_(PRBool) IsTextArea() const;
|
||||
NS_IMETHOD_(PRBool) IsPlainTextControl() const;
|
||||
NS_IMETHOD_(PRBool) IsPasswordTextControl() const;
|
||||
NS_IMETHOD_(PRInt32) GetCols();
|
||||
NS_IMETHOD_(PRInt32) GetWrapCols();
|
||||
NS_IMETHOD_(PRInt32) GetRows();
|
||||
NS_IMETHOD_(void) GetDefaultValueFromContent(nsAString& aValue);
|
||||
NS_IMETHOD_(PRBool) ValueChanged() const;
|
||||
NS_IMETHOD_(void) GetTextEditorValue(nsAString& aValue, PRBool aIgnoreWrap) const;
|
||||
NS_IMETHOD_(void) SetTextEditorValue(const nsAString& aValue, PRBool aUserInput);
|
||||
NS_IMETHOD_(nsIEditor*) GetTextEditor();
|
||||
NS_IMETHOD_(nsISelectionController*) GetSelectionController();
|
||||
NS_IMETHOD_(nsFrameSelection*) GetConstFrameSelection();
|
||||
NS_IMETHOD BindToFrame(nsTextControlFrame* aFrame);
|
||||
NS_IMETHOD_(void) UnbindFromFrame(nsTextControlFrame* aFrame);
|
||||
NS_IMETHOD CreateEditor();
|
||||
NS_IMETHOD_(nsIContent*) GetRootEditorNode();
|
||||
NS_IMETHOD_(nsIContent*) GetPlaceholderNode();
|
||||
NS_IMETHOD_(void) UpdatePlaceholderText(PRBool aNotify);
|
||||
NS_IMETHOD_(void) SetPlaceholderClass(PRBool aVisible, PRBool aNotify);
|
||||
NS_IMETHOD_(void) InitializeKeyboardEventListeners();
|
||||
|
||||
// nsIContent
|
||||
virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
|
||||
@ -172,9 +194,9 @@ public:
|
||||
nsGenericHTMLFormElement)
|
||||
|
||||
protected:
|
||||
using nsGenericHTMLFormElement::IsSingleLineTextControl; // get rid of the compiler warning
|
||||
|
||||
nsCOMPtr<nsIControllers> mControllers;
|
||||
/** The current value. This is null if the frame owns the value. */
|
||||
char* mValue;
|
||||
/** Whether or not the value has changed since its default value was given. */
|
||||
PRPackedBool mValueChanged;
|
||||
/** Whether or not we are already handling select event. */
|
||||
@ -184,6 +206,8 @@ protected:
|
||||
PRPackedBool mDoneAddingChildren;
|
||||
/** Whether our disabled state has changed from the default **/
|
||||
PRPackedBool mDisabledChanged;
|
||||
/** The state of the text editor (selection controller and the editor) **/
|
||||
nsRefPtr<nsTextEditorState> mState;
|
||||
|
||||
NS_IMETHOD SelectAll(nsPresContext* aPresContext);
|
||||
/**
|
||||
@ -196,7 +220,6 @@ protected:
|
||||
void GetValueInternal(nsAString& aValue, PRBool aIgnoreWrap);
|
||||
|
||||
nsresult SetValueInternal(const nsAString& aValue,
|
||||
nsITextControlFrame* aFrame,
|
||||
PRBool aUserInput);
|
||||
nsresult GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd);
|
||||
|
||||
@ -223,22 +246,15 @@ NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(TextArea)
|
||||
nsHTMLTextAreaElement::nsHTMLTextAreaElement(nsINodeInfo *aNodeInfo,
|
||||
PRBool aFromParser)
|
||||
: nsGenericHTMLFormElement(aNodeInfo),
|
||||
mValue(nsnull),
|
||||
mValueChanged(PR_FALSE),
|
||||
mHandlingSelect(PR_FALSE),
|
||||
mDoneAddingChildren(!aFromParser),
|
||||
mDisabledChanged(PR_FALSE)
|
||||
mDisabledChanged(PR_FALSE),
|
||||
mState(new nsTextEditorState(this))
|
||||
{
|
||||
AddMutationObserver(this);
|
||||
}
|
||||
|
||||
nsHTMLTextAreaElement::~nsHTMLTextAreaElement()
|
||||
{
|
||||
if (mValue) {
|
||||
nsMemory::Free(mValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLTextAreaElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLTextAreaElement,
|
||||
@ -248,6 +264,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLTextAreaElement,
|
||||
nsGenericHTMLFormElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mControllers)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mState, nsTextEditorState)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsHTMLTextAreaElement, nsGenericElement)
|
||||
@ -397,79 +414,78 @@ nsHTMLTextAreaElement::GetValue(nsAString& aValue)
|
||||
void
|
||||
nsHTMLTextAreaElement::GetValueInternal(nsAString& aValue, PRBool aIgnoreWrap)
|
||||
{
|
||||
// Get the frame.
|
||||
// No need to flush here, if there is no frame yet for this textarea
|
||||
// there won't be a value in it we don't already have even if we
|
||||
// force the frame to be created.
|
||||
nsIFrame* primaryFrame = GetPrimaryFrame();
|
||||
nsITextControlFrame* textControlFrame = nsnull;
|
||||
if (primaryFrame) {
|
||||
textControlFrame = do_QueryFrame(primaryFrame);
|
||||
}
|
||||
mState->GetValue(aValue, aIgnoreWrap);
|
||||
}
|
||||
|
||||
// If the frame exists and owns the value, get it from the frame. Otherwise
|
||||
// get it from content.
|
||||
PRBool frameOwnsValue = PR_FALSE;
|
||||
if (textControlFrame) {
|
||||
textControlFrame->OwnsValue(&frameOwnsValue);
|
||||
}
|
||||
if (frameOwnsValue) {
|
||||
textControlFrame->GetValue(aValue, aIgnoreWrap);
|
||||
} else {
|
||||
if (!mValueChanged || !mValue) {
|
||||
GetDefaultValue(aValue);
|
||||
} else {
|
||||
CopyUTF8toUTF16(mValue, aValue);
|
||||
}
|
||||
}
|
||||
NS_IMETHODIMP_(nsIEditor*)
|
||||
nsHTMLTextAreaElement::GetTextEditor()
|
||||
{
|
||||
return mState->GetEditor();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsISelectionController*)
|
||||
nsHTMLTextAreaElement::GetSelectionController()
|
||||
{
|
||||
return mState->GetSelectionController();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsFrameSelection*)
|
||||
nsHTMLTextAreaElement::GetConstFrameSelection()
|
||||
{
|
||||
return mState->GetConstFrameSelection();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLTextAreaElement::TakeTextFrameValue(const nsAString& aValue)
|
||||
nsHTMLTextAreaElement::BindToFrame(nsTextControlFrame* aFrame)
|
||||
{
|
||||
if (mValue) {
|
||||
nsMemory::Free(mValue);
|
||||
}
|
||||
nsString value(aValue);
|
||||
nsContentUtils::PlatformToDOMLineBreaks(value);
|
||||
mValue = ToNewUTF8String(value);
|
||||
return NS_OK;
|
||||
return mState->BindToFrame(aFrame);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsHTMLTextAreaElement::UnbindFromFrame(nsTextControlFrame* aFrame)
|
||||
{
|
||||
mState->UnbindFromFrame(aFrame);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLTextAreaElement::CreateEditor()
|
||||
{
|
||||
return mState->PrepareEditor();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsIContent*)
|
||||
nsHTMLTextAreaElement::GetRootEditorNode()
|
||||
{
|
||||
return mState->GetRootNode();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsIContent*)
|
||||
nsHTMLTextAreaElement::GetPlaceholderNode()
|
||||
{
|
||||
return mState->GetPlaceholderNode();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsHTMLTextAreaElement::UpdatePlaceholderText(PRBool aNotify)
|
||||
{
|
||||
mState->UpdatePlaceholderText(aNotify);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsHTMLTextAreaElement::SetPlaceholderClass(PRBool aVisible, PRBool aNotify)
|
||||
{
|
||||
mState->SetPlaceholderClass(aVisible, aNotify);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLTextAreaElement::SetValueInternal(const nsAString& aValue,
|
||||
nsITextControlFrame* aFrame,
|
||||
PRBool aUserInput)
|
||||
{
|
||||
nsITextControlFrame* textControlFrame = aFrame;
|
||||
nsIFormControlFrame* formControlFrame = textControlFrame;
|
||||
if (!textControlFrame) {
|
||||
// No need to flush here, if there is no frame for this yet forcing
|
||||
// creation of one will not do us any good
|
||||
formControlFrame = GetFormControlFrame(PR_FALSE);
|
||||
|
||||
if (formControlFrame) {
|
||||
textControlFrame = do_QueryFrame(formControlFrame);
|
||||
}
|
||||
}
|
||||
|
||||
PRBool frameOwnsValue = PR_FALSE;
|
||||
if (textControlFrame) {
|
||||
textControlFrame->OwnsValue(&frameOwnsValue);
|
||||
}
|
||||
if (frameOwnsValue) {
|
||||
formControlFrame->SetFormProperty(
|
||||
aUserInput ? nsGkAtoms::userInput : nsGkAtoms::value, aValue);
|
||||
}
|
||||
else {
|
||||
if (mValue) {
|
||||
nsMemory::Free(mValue);
|
||||
}
|
||||
mValue = ToNewUTF8String(aValue);
|
||||
NS_ENSURE_TRUE(mValue, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
// Need to set the value changed flag here, so that
|
||||
// nsTextControlFrame::UpdateValueDisplay retrieves the correct value
|
||||
// if needed.
|
||||
SetValueChanged(PR_TRUE);
|
||||
}
|
||||
mState->SetValue(aValue, aUserInput);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -477,7 +493,7 @@ nsHTMLTextAreaElement::SetValueInternal(const nsAString& aValue,
|
||||
NS_IMETHODIMP
|
||||
nsHTMLTextAreaElement::SetValue(const nsAString& aValue)
|
||||
{
|
||||
return SetValueInternal(aValue, nsnull, PR_FALSE);
|
||||
return SetValueInternal(aValue, PR_FALSE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -486,7 +502,7 @@ nsHTMLTextAreaElement::SetUserInput(const nsAString& aValue)
|
||||
if (!nsContentUtils::IsCallerTrustedForWrite()) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
SetValueInternal(aValue, nsnull, PR_TRUE);
|
||||
SetValueInternal(aValue, PR_TRUE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -494,9 +510,8 @@ NS_IMETHODIMP
|
||||
nsHTMLTextAreaElement::SetValueChanged(PRBool aValueChanged)
|
||||
{
|
||||
mValueChanged = aValueChanged;
|
||||
if (!aValueChanged && mValue) {
|
||||
nsMemory::Free(mValue);
|
||||
mValue = nsnull;
|
||||
if (!aValueChanged && !mState->IsEmpty()) {
|
||||
mState->EmptyValue();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1003,3 +1018,101 @@ nsHTMLTextAreaElement::CopyInnerTo(nsGenericElement* aDest) const
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsHTMLTextAreaElement::IsSingleLineTextControl() const
|
||||
{
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsHTMLTextAreaElement::IsTextArea() const
|
||||
{
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsHTMLTextAreaElement::IsPlainTextControl() const
|
||||
{
|
||||
// need to check our HTML attribute and/or CSS.
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsHTMLTextAreaElement::IsPasswordTextControl() const
|
||||
{
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRInt32)
|
||||
nsHTMLTextAreaElement::GetCols()
|
||||
{
|
||||
const nsAttrValue* attr = GetParsedAttr(nsGkAtoms::cols);
|
||||
if (attr) {
|
||||
PRInt32 cols = attr->Type() == nsAttrValue::eInteger ?
|
||||
attr->GetIntegerValue() : 0;
|
||||
// XXX why a default of 1 char, why hide it
|
||||
return (cols <= 0) ? 1 : cols;
|
||||
}
|
||||
|
||||
return DEFAULT_COLS;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRInt32)
|
||||
nsHTMLTextAreaElement::GetWrapCols()
|
||||
{
|
||||
// wrap=off means -1 for wrap width no matter what cols is
|
||||
nsHTMLTextWrap wrapProp;
|
||||
nsITextControlElement::GetWrapPropertyEnum(this, wrapProp);
|
||||
if (wrapProp == nsITextControlElement::eHTMLTextWrap_Off) {
|
||||
// do not wrap when wrap=off
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Otherwise we just wrap at the given number of columns
|
||||
return GetCols();
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP_(PRInt32)
|
||||
nsHTMLTextAreaElement::GetRows()
|
||||
{
|
||||
const nsAttrValue* attr = GetParsedAttr(nsGkAtoms::rows);
|
||||
if (attr && attr->Type() == nsAttrValue::eInteger) {
|
||||
PRInt32 rows = attr->GetIntegerValue();
|
||||
return (rows <= 0) ? DEFAULT_ROWS_TEXTAREA : rows;
|
||||
}
|
||||
|
||||
return DEFAULT_ROWS_TEXTAREA;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsHTMLTextAreaElement::GetDefaultValueFromContent(nsAString& aValue)
|
||||
{
|
||||
GetDefaultValue(aValue);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsHTMLTextAreaElement::ValueChanged() const
|
||||
{
|
||||
return mValueChanged;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsHTMLTextAreaElement::GetTextEditorValue(nsAString& aValue,
|
||||
PRBool aIgnoreWrap) const
|
||||
{
|
||||
mState->GetValue(aValue, aIgnoreWrap);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsHTMLTextAreaElement::SetTextEditorValue(const nsAString& aValue,
|
||||
PRBool aUserInput)
|
||||
{
|
||||
mState->SetValue(aValue, aUserInput);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsHTMLTextAreaElement::InitializeKeyboardEventListeners()
|
||||
{
|
||||
mState->InitializeKeyboardEventListeners();
|
||||
}
|
||||
|
1890
content/html/content/src/nsTextEditorState.cpp
Normal file
1890
content/html/content/src/nsTextEditorState.cpp
Normal file
File diff suppressed because it is too large
Load Diff
239
content/html/content/src/nsTextEditorState.h
Normal file
239
content/html/content/src/nsTextEditorState.h
Normal file
@ -0,0 +1,239 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=2 et tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla.org client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ehsan Akhgari <ehsan@mozilla.com> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsTextEditorState_h__
|
||||
#define nsTextEditorState_h__
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsITextControlElement.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
class nsTextInputListener;
|
||||
class nsTextControlFrame;
|
||||
class nsTextInputSelectionImpl;
|
||||
class nsAnonDivObserver;
|
||||
class nsISelectionController;
|
||||
class nsFrameSelection;
|
||||
class nsIEditor;
|
||||
class nsITextControlElement;
|
||||
|
||||
/**
|
||||
* nsTextEditorState is a class which is responsible for managing the state of
|
||||
* plaintext controls. This currently includes the following HTML elements:
|
||||
* <input type=text>
|
||||
* <input type=password>
|
||||
* <textarea>
|
||||
* and also XUL controls such as <textbox> which use one of these elements behind
|
||||
* the scenes.
|
||||
*
|
||||
* This class is held as a member of nsHTMLInputElement and nsHTMLTextAreaElement.
|
||||
* The public functions in this class include the public APIs which content/ uses.
|
||||
* Layout code uses the nsITextControlElement interface to invoke functions on this
|
||||
* class.
|
||||
*
|
||||
* The design motivation behind this class is maintaining all of the things which
|
||||
* collectively are considered the "state" of the text control in a single location.
|
||||
* This state includes several things:
|
||||
*
|
||||
* * The control's value. This value is stored in the mValue member, and is only
|
||||
* used when there is no frame for the control, or when the editor object has
|
||||
* not been initialized yet.
|
||||
*
|
||||
* * The control's associated frame. This value is stored in the mBoundFrame member.
|
||||
* A text control might never have an associated frame during its life cycle,
|
||||
* or might have several different ones, but at any given moment in time there is
|
||||
* a maximum of 1 bound frame to each text control.
|
||||
*
|
||||
* * The control's associated editor. This value is stored in the mEditor member.
|
||||
* An editor is initilized for the control only when necessary (that is, when either
|
||||
* the user is about to interact with the text control, or when some other code
|
||||
* needs to access the editor object. Without a frame bound to the control, an
|
||||
* editor is never initialzied. Once initialized, the editor might outlive the frame,
|
||||
* in which case the same editor will be used if a new frame gets bound to the
|
||||
* text control.
|
||||
*
|
||||
* * The anonymous content associated with the text control's frame, including the
|
||||
* value div (the DIV element responsible for holding the value of the text control)
|
||||
* and the placeholder div (the DIV element responsible for holding the placeholder
|
||||
* value of the text control.) These values are stored in the mRootNode and
|
||||
* mPlaceholderDiv members, respectively. They will be created when a
|
||||
* frame is bound to the text control. They will be destroyed when the frame is
|
||||
* unbound from the object. We could try and hold on to the anonymous content
|
||||
* between different frames, but unfortunately that is not currently possible
|
||||
* because they are not unbound from the document in time.
|
||||
*
|
||||
* * The frame selection controller. This value is stored in the mSelCon member.
|
||||
* The frame selection controller is responsible for maintaining the selection state
|
||||
* on a frame. It is created when a frame is bound to the text control element,
|
||||
* and will be destroy when the frame is being unbound from the text control element.
|
||||
* It is created alongside with the frame selection object which is stored in the
|
||||
* mFrameSel member.
|
||||
*
|
||||
* * The editor text listener. This value is stored in the mTextListener member.
|
||||
* Its job is to listen to selection and keyboard events, and act accordingly.
|
||||
* It is created when an a frame is first bound to the control, and will be destroyed
|
||||
* when the frame is unbound from the text control element.
|
||||
*
|
||||
* * The editor's cached value. This value is stored in the mCachedValue member.
|
||||
* It is used to improve the performance of append operations to the text
|
||||
* control. A mutation observer stored in the mAnonDivObserver has the job of
|
||||
* invalidating this cache when the anonymous contect containing the value is
|
||||
* changed.
|
||||
*
|
||||
*
|
||||
* As a general rule, nsTextEditorState objects own the value of the text control, and any
|
||||
* attempt to retrieve or set the value must be made through those objects. Internally,
|
||||
* the value can be represented in several different ways, based on the state the control is
|
||||
* in.
|
||||
*
|
||||
* * When the control is first initialized, its value is equal to the default value of
|
||||
* the DOM node. For <input> text controls, this default value is the value of the
|
||||
* value attribute. For <textarea> elements, this default value is the value of the
|
||||
* text node children of the element.
|
||||
*
|
||||
* * If the value has been changed through the DOM node (before the editor for the object
|
||||
* is initialized), the value is stored as a simple string inside the mValue member of
|
||||
* the nsTextEditorState object.
|
||||
*
|
||||
* * If an editor has been initialized for the control, the value is set and retrievd via
|
||||
* the nsIPlaintextEditor interface, and is internally managed by the editor as the
|
||||
* native anonymous content tree attached to the control's frame.
|
||||
*
|
||||
* * If the text editor state object is unbound from the control's frame, the value is
|
||||
* transferred to the mValue member variable, and will be managed there until a new
|
||||
* frame is bound to the text editor state object.
|
||||
*/
|
||||
|
||||
class nsTextEditorState {
|
||||
public:
|
||||
explicit nsTextEditorState(nsITextControlElement* aOwningElement);
|
||||
~nsTextEditorState();
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsTextEditorState)
|
||||
NS_INLINE_DECL_REFCOUNTING(nsTextEditorState)
|
||||
|
||||
nsIEditor* GetEditor();
|
||||
nsISelectionController* GetSelectionController() const;
|
||||
nsFrameSelection* GetConstFrameSelection();
|
||||
nsresult BindToFrame(nsTextControlFrame* aFrame);
|
||||
void UnbindFromFrame(nsTextControlFrame* aFrame);
|
||||
nsresult PrepareEditor(const nsAString *aValue = nsnull);
|
||||
void InitializeKeyboardEventListeners();
|
||||
|
||||
void SetValue(const nsAString& aValue, PRBool aUserInput);
|
||||
void GetValue(nsAString& aValue, PRBool aIgnoreWrap) const;
|
||||
void EmptyValue() { if (mValue) mValue->Truncate(); }
|
||||
PRBool IsEmpty() const { return mValue ? mValue->IsEmpty() : PR_TRUE; }
|
||||
|
||||
nsIContent* GetRootNode() {
|
||||
if (!mRootNode)
|
||||
CreateRootNode();
|
||||
return mRootNode;
|
||||
}
|
||||
nsIContent* GetPlaceholderNode() {
|
||||
if (!mPlaceholderDiv)
|
||||
CreatePlaceholderNode();
|
||||
return mPlaceholderDiv;
|
||||
}
|
||||
|
||||
PRBool IsSingleLineTextControl() const {
|
||||
return mTextCtrlElement->IsSingleLineTextControl();
|
||||
}
|
||||
PRBool IsTextArea() const {
|
||||
return mTextCtrlElement->IsTextArea();
|
||||
}
|
||||
PRBool IsPlainTextControl() const {
|
||||
return mTextCtrlElement->IsPlainTextControl();
|
||||
}
|
||||
PRBool IsPasswordTextControl() const {
|
||||
return mTextCtrlElement->IsPasswordTextControl();
|
||||
}
|
||||
PRInt32 GetCols() {
|
||||
return mTextCtrlElement->GetCols();
|
||||
}
|
||||
PRInt32 GetWrapCols() {
|
||||
return mTextCtrlElement->GetWrapCols();
|
||||
}
|
||||
PRInt32 GetRows() {
|
||||
return mTextCtrlElement->GetRows();
|
||||
}
|
||||
|
||||
// placeholder methods
|
||||
void SetPlaceholderClass(PRBool aVisible, PRBool aNotify);
|
||||
void UpdatePlaceholderText(PRBool aNotify);
|
||||
|
||||
/**
|
||||
* Get the maxlength attribute
|
||||
* @param aMaxLength the value of the max length attr
|
||||
* @returns PR_FALSE if attr not defined
|
||||
*/
|
||||
PRBool GetMaxLength(PRInt32* aMaxLength);
|
||||
|
||||
/* called to free up native keybinding services */
|
||||
static NS_HIDDEN_(void) ShutDown();
|
||||
|
||||
void ClearValueCache() { mCachedValue.Truncate(); }
|
||||
|
||||
private:
|
||||
// not copy constructible
|
||||
nsTextEditorState(const nsTextEditorState&);
|
||||
// not assignable
|
||||
void operator= (const nsTextEditorState&);
|
||||
|
||||
nsresult CreateRootNode();
|
||||
nsresult CreatePlaceholderNode();
|
||||
|
||||
void ValueWasChanged(PRBool aNotify);
|
||||
|
||||
void DestroyEditor();
|
||||
void Clear();
|
||||
|
||||
nsITextControlElement* const mTextCtrlElement;
|
||||
nsRefPtr<nsTextInputSelectionImpl> mSelCon;
|
||||
nsCOMPtr<nsIEditor> mEditor;
|
||||
nsCOMPtr<nsIContent> mRootNode;
|
||||
nsCOMPtr<nsIContent> mPlaceholderDiv;
|
||||
nsTextControlFrame* mBoundFrame;
|
||||
nsTextInputListener* mTextListener;
|
||||
nsAutoPtr<nsCString> mValue;
|
||||
nsRefPtr<nsAnonDivObserver> mMutationObserver;
|
||||
mutable nsString mCachedValue; // Caches non-hard-wrapped value on a multiline control.
|
||||
PRPackedBool mEditorInitialized;
|
||||
};
|
||||
|
||||
#endif
|
@ -134,7 +134,6 @@ extern nsIParserService *sParserService;
|
||||
nsEditor::nsEditor()
|
||||
: mModCount(0)
|
||||
, mPresShellWeak(nsnull)
|
||||
, mViewManager(nsnull)
|
||||
, mUpdateCount(0)
|
||||
, mSpellcheckCheckboxState(eTriUnset)
|
||||
, mPlaceHolderTxn(nsnull)
|
||||
@ -166,8 +165,6 @@ nsEditor::~nsEditor()
|
||||
mTxnMgr = nsnull;
|
||||
|
||||
delete mPhonetic;
|
||||
|
||||
NS_IF_RELEASE(mViewManager);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsEditor)
|
||||
@ -252,7 +249,6 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIPresShell* aPresShell, nsIContent *aRoot
|
||||
|
||||
mViewManager = ps->GetViewManager();
|
||||
if (!mViewManager) {return NS_ERROR_NULL_POINTER;}
|
||||
NS_ADDREF(mViewManager);
|
||||
|
||||
mUpdateCount=0;
|
||||
|
||||
@ -281,6 +277,9 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIPresShell* aPresShell, nsIContent *aRoot
|
||||
|
||||
NS_POSTCONDITION(mDocWeak && mPresShellWeak, "bad state");
|
||||
|
||||
// Make sure that the editor will be destroyed properly
|
||||
mDidPreDestroy = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -318,7 +317,9 @@ nsEditor::PostCreate()
|
||||
nsresult
|
||||
nsEditor::CreateEventListeners()
|
||||
{
|
||||
NS_ENSURE_TRUE(!mEventListener, NS_ERROR_ALREADY_INITIALIZED);
|
||||
// Don't create the handler twice
|
||||
if (mEventListener)
|
||||
return NS_OK;
|
||||
mEventListener = do_QueryInterface(
|
||||
static_cast<nsIDOMKeyListener*>(new nsEditorEventListener()));
|
||||
NS_ENSURE_TRUE(mEventListener, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
@ -657,7 +657,7 @@ protected:
|
||||
|
||||
nsWeakPtr mPresShellWeak; // weak reference to the nsIPresShell
|
||||
nsWeakPtr mSelConWeak; // weak reference to the nsISelectionController
|
||||
nsIViewManager *mViewManager;
|
||||
nsCOMPtr<nsIViewManager> mViewManager;
|
||||
PRInt32 mUpdateCount;
|
||||
nsIViewManager::UpdateViewBatch mBatch;
|
||||
|
||||
|
@ -97,7 +97,6 @@ nsresult
|
||||
nsEditorEventListener::Connect(nsEditor* aEditor)
|
||||
{
|
||||
NS_ENSURE_ARG(aEditor);
|
||||
NS_ENSURE_TRUE(!mEditor, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
mEditor = aEditor;
|
||||
|
||||
|
@ -360,7 +360,6 @@ nsLayoutStatics::Shutdown()
|
||||
nsJSRuntime::Shutdown();
|
||||
nsGlobalWindow::ShutDown();
|
||||
nsDOMClassInfo::ShutDown();
|
||||
nsTextControlFrame::ShutDown();
|
||||
nsListControlFrame::Shutdown();
|
||||
nsXBLWindowKeyHandler::ShutDown();
|
||||
nsAutoCopyListener::Shutdown();
|
||||
|
@ -142,19 +142,11 @@ NS_IMPL_FRAMEARENA_HELPERS(nsFileControlFrame)
|
||||
|
||||
nsFileControlFrame::nsFileControlFrame(nsStyleContext* aContext):
|
||||
nsBlockFrame(aContext),
|
||||
mTextFrame(nsnull),
|
||||
mCachedState(nsnull)
|
||||
mTextFrame(nsnull)
|
||||
{
|
||||
AddStateBits(NS_BLOCK_FLOAT_MGR);
|
||||
}
|
||||
|
||||
nsFileControlFrame::~nsFileControlFrame()
|
||||
{
|
||||
if (mCachedState) {
|
||||
delete mCachedState;
|
||||
mCachedState = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileControlFrame::Init(nsIContent* aContent,
|
||||
@ -675,11 +667,6 @@ NS_IMETHODIMP nsFileControlFrame::Reflow(nsPresContext* aPresContext,
|
||||
if (mState & NS_FRAME_FIRST_REFLOW) {
|
||||
mTextFrame = GetTextControlFrame(aPresContext, this);
|
||||
NS_ENSURE_TRUE(mTextFrame, NS_ERROR_UNEXPECTED);
|
||||
if (mCachedState) {
|
||||
mTextFrame->SetFormProperty(nsGkAtoms::value, *mCachedState);
|
||||
delete mCachedState;
|
||||
mCachedState = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
// nsBlockFrame takes care of all our reflow
|
||||
@ -785,13 +772,11 @@ nsFileControlFrame::SetFormProperty(nsIAtom* aName,
|
||||
const nsAString& aValue)
|
||||
{
|
||||
if (nsGkAtoms::value == aName) {
|
||||
if (mTextFrame) {
|
||||
mTextFrame->SetValue(aValue);
|
||||
} else {
|
||||
if (mCachedState) delete mCachedState;
|
||||
mCachedState = new nsString(aValue);
|
||||
NS_ENSURE_TRUE(mCachedState, NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
nsCOMPtr<nsIDOMHTMLInputElement> textControl =
|
||||
do_QueryInterface(mTextContent);
|
||||
NS_ASSERTION(textControl,
|
||||
"The text control should exist and be an input element");
|
||||
textControl->SetValue(aValue);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -53,7 +53,6 @@ class nsFileControlFrame : public nsBlockFrame,
|
||||
{
|
||||
public:
|
||||
nsFileControlFrame(nsStyleContext* aContext);
|
||||
virtual ~nsFileControlFrame();
|
||||
|
||||
NS_IMETHOD Init(nsIContent* aContent,
|
||||
nsIFrame* aParent,
|
||||
@ -168,11 +167,6 @@ protected:
|
||||
* @see nsFileControlFrame::CreateAnonymousContent
|
||||
*/
|
||||
nsCOMPtr<nsIContent> mBrowse;
|
||||
/**
|
||||
* The current value, stored during those rare in-between periods where the
|
||||
* file frame is there but the input frame is not.
|
||||
*/
|
||||
nsString* mCachedState;
|
||||
|
||||
/**
|
||||
* Our mouse listener. This makes sure we don't get used after destruction.
|
||||
|
@ -52,24 +52,6 @@ public:
|
||||
|
||||
NS_IMETHOD GetEditor(nsIEditor **aEditor) = 0;
|
||||
|
||||
/**
|
||||
* Tell whether the frame currently owns the value or the content does (for
|
||||
* edge cases where the frame has just been created or is just going away).
|
||||
*
|
||||
* @param aOwnsValue whether the frame owns the value [out]
|
||||
*/
|
||||
NS_IMETHOD OwnsValue(PRBool* aOwnsValue) = 0;
|
||||
|
||||
/**
|
||||
* Get the current value, either from the editor or from the textarea.
|
||||
*
|
||||
* @param aValue the value [out]
|
||||
* @param aIgnoreWrap whether to ignore the wrap attribute when getting the
|
||||
* value. If this is true, linebreaks will not be inserted even if
|
||||
* wrap=hard.
|
||||
*/
|
||||
NS_IMETHOD GetValue(nsAString& aValue, PRBool aIgnoreWrap) const = 0;
|
||||
|
||||
NS_IMETHOD GetTextLength(PRInt32* aTextLength) = 0;
|
||||
|
||||
/**
|
||||
@ -83,7 +65,7 @@ public:
|
||||
NS_IMETHOD SetSelectionRange(PRInt32 aSelectionStart, PRInt32 aSelectionEnd) = 0;
|
||||
NS_IMETHOD GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd) = 0;
|
||||
|
||||
virtual nsISelectionController* GetOwnedSelectionController() = 0;
|
||||
NS_IMETHOD GetOwnedSelectionController(nsISelectionController** aSelCon) = 0;
|
||||
virtual nsFrameSelection* GetOwnedFrameSelection() = 0;
|
||||
|
||||
virtual nsresult GetPhonetic(nsAString& aPhonetic) = 0;
|
||||
|
@ -160,20 +160,18 @@ nsIsIndexFrame::GetInputFrame(nsIFormControlFrame** oFrame)
|
||||
void
|
||||
nsIsIndexFrame::GetInputValue(nsString& oString)
|
||||
{
|
||||
nsIFormControlFrame* frame = nsnull;
|
||||
GetInputFrame(&frame);
|
||||
if (frame) {
|
||||
((nsNewFrame*)frame)->GetValue(oString, PR_FALSE);
|
||||
nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(mInputContent);
|
||||
if (txtCtrl) {
|
||||
txtCtrl->GetTextEditorValue(oString, PR_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsIsIndexFrame::SetInputValue(const nsString& aString)
|
||||
{
|
||||
nsIFormControlFrame* frame = nsnull;
|
||||
GetInputFrame(&frame);
|
||||
if (frame) {
|
||||
((nsNewFrame*)frame)->SetValue(aString);
|
||||
nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(mInputContent);
|
||||
if (txtCtrl) {
|
||||
txtCtrl->SetTextEditorValue(aString, PR_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -41,44 +41,21 @@
|
||||
#include "nsStackFrame.h"
|
||||
#include "nsBlockFrame.h"
|
||||
#include "nsIFormControlFrame.h"
|
||||
#include "nsIDOMMouseListener.h"
|
||||
#include "nsIAnonymousContentCreator.h"
|
||||
#include "nsIEditor.h"
|
||||
#include "nsITextControlFrame.h"
|
||||
#include "nsIFontMetrics.h"
|
||||
#include "nsWeakReference.h" //for service and presshell pointers
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsIScrollableFrame.h"
|
||||
#include "nsStubMutationObserver.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsITextControlElement.h"
|
||||
|
||||
class nsIEditor;
|
||||
class nsISelectionController;
|
||||
class nsTextInputSelectionImpl;
|
||||
class nsTextInputListener;
|
||||
class nsIDOMCharacterData;
|
||||
#ifdef ACCESSIBILITY
|
||||
class nsIAccessible;
|
||||
#endif
|
||||
class nsTextInputSelectionImpl;
|
||||
class nsTextControlFrame;
|
||||
class EditorInitializerEntryTracker;
|
||||
|
||||
class nsAnonDivObserver : public nsStubMutationObserver
|
||||
{
|
||||
public:
|
||||
nsAnonDivObserver(nsTextControlFrame* aTextControl)
|
||||
: mTextControl(aTextControl) {}
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||
|
||||
private:
|
||||
nsTextControlFrame* mTextControl;
|
||||
};
|
||||
class nsTextEditorState;
|
||||
|
||||
class nsTextControlFrame : public nsStackFrame,
|
||||
public nsIAnonymousContentCreator,
|
||||
@ -145,10 +122,6 @@ public:
|
||||
|
||||
// Utility methods to set current widget state
|
||||
|
||||
// Be careful when using this method.
|
||||
// Calling it may cause |this| to be deleted.
|
||||
// In that case the method returns an error value.
|
||||
nsresult SetValue(const nsAString& aValue);
|
||||
NS_IMETHOD SetInitialChildList(nsIAtom* aListName,
|
||||
nsFrameList& aChildList);
|
||||
|
||||
@ -163,17 +136,14 @@ public:
|
||||
//==== NSITEXTCONTROLFRAME
|
||||
|
||||
NS_IMETHOD GetEditor(nsIEditor **aEditor);
|
||||
NS_IMETHOD OwnsValue(PRBool* aOwnsValue);
|
||||
NS_IMETHOD GetValue(nsAString& aValue, PRBool aIgnoreWrap) const;
|
||||
NS_IMETHOD GetTextLength(PRInt32* aTextLength);
|
||||
NS_IMETHOD CheckFireOnChange();
|
||||
NS_IMETHOD SetSelectionStart(PRInt32 aSelectionStart);
|
||||
NS_IMETHOD SetSelectionEnd(PRInt32 aSelectionEnd);
|
||||
NS_IMETHOD SetSelectionRange(PRInt32 aSelectionStart, PRInt32 aSelectionEnd);
|
||||
NS_IMETHOD GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd);
|
||||
virtual nsISelectionController* GetOwnedSelectionController();
|
||||
virtual nsFrameSelection* GetOwnedFrameSelection()
|
||||
{ return mFrameSel; }
|
||||
NS_IMETHOD GetOwnedSelectionController(nsISelectionController** aSelCon);
|
||||
virtual nsFrameSelection* GetOwnedFrameSelection();
|
||||
|
||||
nsresult GetPhonetic(nsAString& aPhonetic);
|
||||
|
||||
@ -198,26 +168,6 @@ public:
|
||||
NS_DECL_QUERYFRAME
|
||||
|
||||
public: //for methods who access nsTextControlFrame directly
|
||||
/**
|
||||
* Find out whether this is a single line text control. (text or password)
|
||||
* @return whether this is a single line text control
|
||||
*/
|
||||
PRBool IsSingleLineTextControl() const;
|
||||
/**
|
||||
* Find out whether this control is a textarea.
|
||||
* @return whether this is a textarea text control
|
||||
*/
|
||||
PRBool IsTextArea() const;
|
||||
/**
|
||||
* Find out whether this control edits plain text. (Currently always true.)
|
||||
* @return whether this is a plain text control
|
||||
*/
|
||||
PRBool IsPlainTextControl() const;
|
||||
/**
|
||||
* Find out whether this is a password control (input type=password)
|
||||
* @return whether this is a password ontrol
|
||||
*/
|
||||
PRBool IsPasswordTextControl() const;
|
||||
void FireOnInput();
|
||||
void SetValueChanged(PRBool aValueChanged);
|
||||
/** Called when the frame is focused, to remember the value for onChange. */
|
||||
@ -233,17 +183,92 @@ public: //for methods who access nsTextControlFrame directly
|
||||
return mFireChangeEventState;
|
||||
}
|
||||
|
||||
/* called to free up native keybinding services */
|
||||
static NS_HIDDEN_(void) ShutDown();
|
||||
|
||||
// called by the focus listener
|
||||
nsresult MaybeBeginSecureKeyboardInput();
|
||||
void MaybeEndSecureKeyboardInput();
|
||||
|
||||
void ClearValueCache() { mCachedValue.Truncate(); }
|
||||
class ValueSetter {
|
||||
public:
|
||||
ValueSetter(nsTextControlFrame* aFrame,
|
||||
PRBool aHasFocusValue)
|
||||
: mFrame(aFrame)
|
||||
, mInited(PR_FALSE)
|
||||
{
|
||||
NS_ASSERTION(aFrame, "Should pass a valid frame");
|
||||
|
||||
// This method isn't used for user-generated changes, except for calls
|
||||
// from nsFileControlFrame which sets mFireChangeEventState==true and
|
||||
// restores it afterwards (ie. we want 'change' events for those changes).
|
||||
// Focused value must be updated to prevent incorrect 'change' events,
|
||||
// but only if user hasn't changed the value.
|
||||
mFocusValueInit = !mFrame->mFireChangeEventState && aHasFocusValue;
|
||||
}
|
||||
void Cancel() {
|
||||
mInited = PR_FALSE;
|
||||
}
|
||||
void Init() {
|
||||
// Since this code does not handle user-generated changes to the text,
|
||||
// make sure we don't fire oninput when the editor notifies us.
|
||||
// (mNotifyOnInput must be reset before we return).
|
||||
|
||||
// To protect against a reentrant call to SetValue, we check whether
|
||||
// another SetValue is already happening for this frame. If it is,
|
||||
// we must wait until we unwind to re-enable oninput events.
|
||||
mOuterTransaction = mFrame->mNotifyOnInput;
|
||||
if (mOuterTransaction)
|
||||
mFrame->mNotifyOnInput = PR_FALSE;
|
||||
|
||||
mInited = PR_TRUE;
|
||||
}
|
||||
~ValueSetter() {
|
||||
if (!mInited)
|
||||
return;
|
||||
|
||||
if (mOuterTransaction)
|
||||
mFrame->mNotifyOnInput = PR_TRUE;
|
||||
|
||||
if (mFocusValueInit) {
|
||||
// Reset mFocusedValue so the onchange event doesn't fire incorrectly.
|
||||
mFrame->InitFocusedValue();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsTextControlFrame* mFrame;
|
||||
PRPackedBool mFocusValueInit;
|
||||
PRPackedBool mOuterTransaction;
|
||||
PRPackedBool mInited;
|
||||
};
|
||||
friend class ValueSetter;
|
||||
|
||||
#define DEFINE_TEXTCTRL_FORWARDER(type, name) \
|
||||
type name() { \
|
||||
nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent()); \
|
||||
NS_ASSERTION(txtCtrl, "Content not a text control element"); \
|
||||
return txtCtrl->name(); \
|
||||
}
|
||||
#define DEFINE_TEXTCTRL_CONST_FORWARDER(type, name) \
|
||||
type name() const { \
|
||||
nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent()); \
|
||||
NS_ASSERTION(txtCtrl, "Content not a text control element"); \
|
||||
return txtCtrl->name(); \
|
||||
}
|
||||
|
||||
DEFINE_TEXTCTRL_CONST_FORWARDER(PRBool, IsSingleLineTextControl)
|
||||
DEFINE_TEXTCTRL_CONST_FORWARDER(PRBool, IsTextArea)
|
||||
DEFINE_TEXTCTRL_CONST_FORWARDER(PRBool, IsPlainTextControl)
|
||||
DEFINE_TEXTCTRL_CONST_FORWARDER(PRBool, IsPasswordTextControl)
|
||||
DEFINE_TEXTCTRL_FORWARDER(PRInt32, GetCols)
|
||||
DEFINE_TEXTCTRL_FORWARDER(PRInt32, GetWrapCols)
|
||||
DEFINE_TEXTCTRL_FORWARDER(PRInt32, GetRows)
|
||||
|
||||
#undef DEFINE_TEXTCTRL_CONST_FORWARDER
|
||||
#undef DEFINE_TEXTCTRL_FORWARDER
|
||||
|
||||
protected:
|
||||
class EditorInitializer;
|
||||
friend class EditorInitializer;
|
||||
friend class nsTextEditorState; // needs access to UpdateValueDisplay
|
||||
|
||||
class EditorInitializer : public nsRunnable {
|
||||
public:
|
||||
@ -257,7 +282,7 @@ protected:
|
||||
mWeakFrame.GetFrame()->PresContext()->GetPresShell();
|
||||
PRBool observes = shell->ObservesNativeAnonMutationsForPrint();
|
||||
shell->ObserveNativeAnonMutationsForPrint(PR_TRUE);
|
||||
mFrame->EnsureEditorInitializedInternal();
|
||||
mFrame->EnsureEditorInitialized();
|
||||
shell->ObserveNativeAnonMutationsForPrint(observes);
|
||||
}
|
||||
return NS_OK;
|
||||
@ -326,24 +351,6 @@ protected:
|
||||
*/
|
||||
void PreDestroy();
|
||||
|
||||
// Helper methods
|
||||
/**
|
||||
* Get the cols attribute (if textarea) or a default
|
||||
* @return the number of columns to use
|
||||
*/
|
||||
PRInt32 GetCols();
|
||||
|
||||
/**
|
||||
* Get the column index to wrap at, or -1 if we shouldn't wrap
|
||||
*/
|
||||
PRInt32 GetWrapCols();
|
||||
|
||||
/**
|
||||
* Get the rows attribute (if textarea) or a default
|
||||
* @return the number of rows to use
|
||||
*/
|
||||
PRInt32 GetRows();
|
||||
|
||||
// Compute our intrinsic size. This does not include any borders, paddings,
|
||||
// etc. Just the size of our actual area for the text (and the scrollbars,
|
||||
// for <textarea>).
|
||||
@ -357,29 +364,20 @@ private:
|
||||
nsresult SelectAllOrCollapseToEndOfText(PRBool aSelect);
|
||||
nsresult SetSelectionEndPoints(PRInt32 aSelStart, PRInt32 aSelEnd);
|
||||
|
||||
// placeholder methods
|
||||
nsresult CreatePlaceholderDiv(nsTArray<nsIContent*>& aElements, nsNodeInfoManager* pNodeInfoManager);
|
||||
nsresult ShowPlaceholder();
|
||||
nsresult HidePlaceholder();
|
||||
nsresult SetPlaceholderClass(PRBool aVisible, PRBool aNotify);
|
||||
nsresult UpdatePlaceholderText(PRBool aNotify);
|
||||
// accessors for the notify on input flag
|
||||
PRBool GetNotifyOnInput() const { return mNotifyOnInput; }
|
||||
void SetNotifyOnInput(PRBool val) { mNotifyOnInput = val; }
|
||||
|
||||
// This method performs the actual tasks of initializing the editor.
|
||||
// EnsureEditorInitialized is a wrapper of this method which wraps it with
|
||||
// a weak frame check.
|
||||
virtual nsresult EnsureEditorInitializedInternal();
|
||||
/**
|
||||
* Return the root DOM element, and implicitly initialize the editor if needed.
|
||||
*/
|
||||
nsresult GetRootNodeAndInitializeEditor(nsIDOMElement **aRootElement);
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIContent> mValueDiv;
|
||||
nsCOMPtr<nsIContent> mPlaceholderDiv;
|
||||
|
||||
nsCOMPtr<nsIEditor> mEditor;
|
||||
|
||||
// these packed bools could instead use the high order bits on mState, saving 4 bytes
|
||||
PRPackedBool mUseEditor;
|
||||
PRPackedBool mIsProcessing;
|
||||
PRPackedBool mNotifyOnInput;//default this to off to stop any notifications until setup is complete
|
||||
PRPackedBool mDidPreDestroy; // has PreDestroy been called
|
||||
// Calls to SetValue will be treated as user values (i.e. trigger onChange
|
||||
// eventually) when mFireChangeEventState==true, this is used by nsFileControlFrame.
|
||||
PRPackedBool mFireChangeEventState;
|
||||
@ -390,12 +388,7 @@ private:
|
||||
friend class EditorInitializerEntryTracker;
|
||||
#endif
|
||||
|
||||
nsRefPtr<nsTextInputSelectionImpl> mSelCon;
|
||||
nsCOMPtr<nsFrameSelection> mFrameSel;
|
||||
nsTextInputListener* mTextListener;
|
||||
nsString mFocusedValue;
|
||||
nsString mCachedValue; // Caches non-hard-wrapped value on a multiline control.
|
||||
nsRefPtr<nsAnonDivObserver> mMutationObserver;
|
||||
nsRevocableEventPtr<ScrollOnFocusEvent> mScrollEvent;
|
||||
};
|
||||
|
||||
|
@ -62,6 +62,7 @@ _TEST_FILES = test_bug231389.html \
|
||||
test_textarea_resize.html \
|
||||
test_bug478219.xhtml \
|
||||
test_bug542914.html \
|
||||
test_bug534785.html \
|
||||
test_bug536567.html \
|
||||
bug536567_subframe.html \
|
||||
test_bug549170.html \
|
||||
|
89
layout/forms/test/test_bug534785.html
Normal file
89
layout/forms/test/test_bug534785.html
Normal file
@ -0,0 +1,89 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=534785
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 534785</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=534785">Mozilla Bug 534785</a>
|
||||
<p id="display"></p>
|
||||
<input type="text" value="test">
|
||||
<div id="reframe">
|
||||
<textarea></textarea>
|
||||
<textarea>test</textarea>
|
||||
<input type="text">
|
||||
<input type="text" value="test">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 534785 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SimpleTest.waitForFocus(function() {
|
||||
var i = document.querySelector("input");
|
||||
i.addEventListener("focus", function() {
|
||||
is(i.value, "test", "Sanity check");
|
||||
|
||||
is(document.activeElement, i, "Should be focused before frame reconstruction");
|
||||
synthesizeKey("1", {});
|
||||
is(i.value, "test1", "Can accept keyboard events before frame reconstruction");
|
||||
|
||||
// force frame reconstruction
|
||||
i.style.display = "none";
|
||||
document.offsetHeight;
|
||||
i.style.display = "";
|
||||
document.offsetHeight;
|
||||
|
||||
is(document.activeElement, i, "Should be focused after frame reconstruction");
|
||||
synthesizeKey("2", {});
|
||||
is(i.value, "test12", "Can accept keyboard events after frame reconstruction");
|
||||
|
||||
// Make sure reframing happens gracefully
|
||||
var reframeDiv = document.getElementById("reframe");
|
||||
var textAreaWithoutValue = reframeDiv.querySelectorAll("textarea")[0];
|
||||
var textAreaWithValue = reframeDiv.querySelectorAll("textarea")[1];
|
||||
var inputWithoutValue = reframeDiv.querySelectorAll("input")[0];
|
||||
var inputWithValue = reframeDiv.querySelectorAll("input")[1];
|
||||
reframeDiv.style.display = "none";
|
||||
document.body.offsetWidth;
|
||||
reframeDiv.style.display = "";
|
||||
document.body.offsetWidth;
|
||||
[textAreaWithoutValue, inputWithoutValue].forEach(function (elem) {
|
||||
is(elem.value, "", "Value should persist correctly");
|
||||
});
|
||||
[textAreaWithValue, inputWithValue].forEach(function (elem) {
|
||||
is(elem.value, "test", "Value should persist correctly");
|
||||
});
|
||||
[inputWithoutValue, inputWithValue].forEach(function (elem) elem.type = "submit");
|
||||
document.body.offsetWidth;
|
||||
is(inputWithoutValue.value, "", "Value should persist correctly");
|
||||
is(inputWithValue.value, "test", "Value should persist correctly");
|
||||
[inputWithoutValue, inputWithValue].forEach(function (elem) elem.type = "text");
|
||||
document.body.offsetWidth;
|
||||
is(inputWithoutValue.value, "", "Value should persist correctly");
|
||||
is(inputWithValue.value, "test", "Value should persist correctly");
|
||||
[inputWithoutValue, inputWithValue].forEach(function (elem) elem.focus()); // initialze the editor
|
||||
reframeDiv.style.display = "none";
|
||||
document.body.offsetWidth;
|
||||
reframeDiv.style.display = "";
|
||||
document.body.offsetWidth;
|
||||
is(inputWithoutValue.value, "", "Value should persist correctly with editor");
|
||||
is(inputWithValue.value, "test", "Value should persist correctly with editor");
|
||||
|
||||
SimpleTest.finish();
|
||||
}, false);
|
||||
i.focus();
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -4315,8 +4315,7 @@ nsFrame::GetSelectionController(nsPresContext *aPresContext, nsISelectionControl
|
||||
while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
|
||||
nsITextControlFrame *tcf = do_QueryFrame(frame);
|
||||
if (tcf) {
|
||||
NS_IF_ADDREF(*aSelCon = tcf->GetOwnedSelectionController());
|
||||
return NS_OK;
|
||||
return tcf->GetOwnedSelectionController(aSelCon);
|
||||
}
|
||||
frame = frame->GetParent();
|
||||
}
|
||||
|
@ -10,18 +10,35 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=527306
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
</head>
|
||||
<body onload="showText()">
|
||||
<body onload="runTests()">
|
||||
<p><a target="_blank" href="https://bugzilla.mozilla.org/show_bug?id=527306">Mozilla Bug 527306</a>
|
||||
|
||||
<p><input type="text" id="currenttext" value="FAIL">
|
||||
<p><input type="text" id="t1" value="FAIL"></p>
|
||||
<p><input type="text" id="t2" value="FAIL"></p>
|
||||
<p><input type="text" id="t3" value="FAIL"></p>
|
||||
<p><textarea id="t4">FAIL</textarea></p>
|
||||
|
||||
<pre id="test">
|
||||
<script>
|
||||
function showText() {
|
||||
var t = document.getElementById("currenttext");
|
||||
|
||||
function testElement(t) {
|
||||
t.style.display = "none";
|
||||
t.value = "PASS";
|
||||
is(t.value, "PASS", "Value should be set correctly");
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
var t = document.getElementById("t1");
|
||||
testElement(t);
|
||||
t = document.getElementById("t2");
|
||||
t.focus();
|
||||
testElement(t);
|
||||
t = document.getElementById("t3");
|
||||
t.focus();
|
||||
t.blur();
|
||||
testElement(t);
|
||||
t = document.getElementById("t4");
|
||||
testElement(t);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
11
layout/reftests/editor/dynamic-type-1.html
Normal file
11
layout/reftests/editor/dynamic-type-1.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<input type="checkbox">
|
||||
<script>
|
||||
var i = document.getElementsByTagName("input")[0];
|
||||
i.type = "text";
|
||||
i.value = "abcdef";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
11
layout/reftests/editor/dynamic-type-2.html
Normal file
11
layout/reftests/editor/dynamic-type-2.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<input type="checkbox">
|
||||
<script>
|
||||
var i = document.getElementsByTagName("input")[0];
|
||||
i.value = "abcdef";
|
||||
i.type = "text";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
11
layout/reftests/editor/dynamic-type-3.html
Normal file
11
layout/reftests/editor/dynamic-type-3.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<input type="checkbox" value="foo">
|
||||
<script>
|
||||
var i = document.getElementsByTagName("input")[0];
|
||||
i.type = "text";
|
||||
i.value = "abcdef";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
11
layout/reftests/editor/dynamic-type-4.html
Normal file
11
layout/reftests/editor/dynamic-type-4.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<input type="checkbox" value="foo">
|
||||
<script>
|
||||
var i = document.getElementsByTagName("input")[0];
|
||||
i.type = "text";
|
||||
i.value = "abcdef";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -5,6 +5,10 @@ include xul/reftest.list
|
||||
== newline-2.html newline-ref.html
|
||||
== newline-3.html newline-ref.html
|
||||
== dynamic-1.html dynamic-ref.html
|
||||
== dynamic-type-1.html dynamic-ref.html
|
||||
== dynamic-type-2.html dynamic-ref.html
|
||||
== dynamic-type-3.html dynamic-ref.html
|
||||
== dynamic-type-4.html dynamic-ref.html
|
||||
== passwd-1.html passwd-ref.html
|
||||
!= passwd-2.html passwd-ref.html
|
||||
== passwd-3.html passwd-ref.html
|
||||
|
22
layout/reftests/forms/placeholder/placeholder-18.html
Normal file
22
layout/reftests/forms/placeholder/placeholder-18.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<!-- Test: placeholder should appear with dynamic DOM modifications -->
|
||||
<script type="text/javascript">
|
||||
function setPlaceholder()
|
||||
{
|
||||
var i = document.getElementById('p1');
|
||||
i.focus();
|
||||
i.blur();
|
||||
i.value = "not empty";
|
||||
i.value = "";
|
||||
i.value = "my value";
|
||||
}
|
||||
function disableReftestWait()
|
||||
{
|
||||
document.documentElement.className = '';
|
||||
}
|
||||
</script>
|
||||
<body onload="setPlaceholder(); disableReftestWait();">
|
||||
<input type="text" id="p1" value="" placeholder="my placeholder">
|
||||
</body>
|
||||
</html>
|
@ -18,3 +18,4 @@
|
||||
== placeholder-15.html placeholder-focus-ref.html
|
||||
== placeholder-16.html placeholder-focus-ref.html
|
||||
== placeholder-17.html placeholder-focus-ref.html
|
||||
== placeholder-18.html placeholder-overridden-ref.html
|
||||
|
@ -18,6 +18,7 @@ HTTP(..) == text-control-baseline-1.html text-control-baseline-1-ref.html
|
||||
!= textarea-in-ltr-doc-scrollbar.html textarea-in-rtl-doc-scrollbar.html
|
||||
!= textarea-ltr.html textarea-no-resize.html
|
||||
random-if(MOZ_WIDGET_TOOLKIT=="gtk2") != textarea-rtl.html textarea-no-resize.html # bug 558201
|
||||
== textarea-setvalue-framereconstruction-1.html textarea-setvalue-framereconstruction-ref.html
|
||||
|
||||
== radio-label-dynamic.html radio-label-dynamic-ref.html
|
||||
== out-of-bounds-selectedindex.html out-of-bounds-selectedindex-ref.html # test for bug 471741
|
||||
|
@ -0,0 +1,48 @@
|
||||
<!--
|
||||
|
||||
This test is mostly a copy of layout/forms/crashtests/373586-1.xhtml,
|
||||
and it makes sure that the value setter works correctly when setting
|
||||
the value causes the frame to be reconstructed.
|
||||
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
|
||||
<head>
|
||||
|
||||
<bindings xmlns="http://www.mozilla.org/xbl">
|
||||
<binding id="foo">
|
||||
<content>
|
||||
<children xmlns="http://www.mozilla.org/xbl" />
|
||||
</content>
|
||||
</binding>
|
||||
</bindings>
|
||||
|
||||
<script>
|
||||
function boom()
|
||||
{
|
||||
document.getElementById("div").style.MozBinding = "url('#foo')";
|
||||
|
||||
var opt1 = document.getElementById("opt1");
|
||||
opt1.removeChild(opt1.firstChild);
|
||||
|
||||
document.getElementById("textarea").value += " y";
|
||||
|
||||
document.getElementById("div").style.MozBinding = "";
|
||||
document.documentElement.removeAttribute("class")
|
||||
}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="setTimeout(boom, 30);">
|
||||
|
||||
<div id="div">
|
||||
<textarea rows="3" cols="5" id="textarea">x</textarea>
|
||||
</div>
|
||||
|
||||
<select>
|
||||
<option id="opt1">opt1</option>
|
||||
</select>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -0,0 +1,17 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="div">
|
||||
<textarea rows="3" cols="5" id="textarea">x y</textarea>
|
||||
</div>
|
||||
|
||||
<select>
|
||||
<option id="opt1"></option>
|
||||
</select>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user