Bug 388558, 'change' event isn't dispatched if user selects input field value from the autocomplete list, r=jst, sr=sicking, a=mconnor

This commit is contained in:
Olli.Pettay@helsinki.fi 2007-10-02 09:56:07 -07:00
parent 4a6f6dbd20
commit a6b454f086
8 changed files with 152 additions and 18 deletions

View File

@ -1159,6 +1159,7 @@ GK_ATOM(tref, "tref")
GK_ATOM(tspan, "tspan")
GK_ATOM(turbulence, "turbulence")
GK_ATOM(unicode_bidi, "unicode-bidi")
GK_ATOM(userInput, "userInput")
GK_ATOM(userSpaceOnUse, "userSpaceOnUse")
GK_ATOM(view, "view")
GK_ATOM(viewBox, "viewBox")

View File

@ -179,7 +179,11 @@ public:
NS_DECL_NSIPHONETIC
// nsIDOMNSEditableElement
NS_FORWARD_NSIDOMNSEDITABLEELEMENT(nsGenericHTMLElement::)
NS_IMETHOD GetEditor(nsIEditor** aEditor)
{
return nsGenericHTMLElement::GetEditor(aEditor);
}
NS_IMETHOD SetUserInput(const nsAString& aInput);
// Overriden nsIFormControl methods
NS_IMETHOD_(PRInt32) GetType() const { return mType; }
@ -250,7 +254,8 @@ public:
protected:
// Helper method
nsresult SetValueInternal(const nsAString& aValue,
nsITextControlFrame* aFrame);
nsITextControlFrame* aFrame,
PRBool aUserInput);
nsresult GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd);
@ -444,7 +449,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);
it->SetValueInternal(value, nsnull, PR_FALSE);
}
break;
case NS_FORM_INPUT_FILE:
@ -783,12 +788,28 @@ nsHTMLInputElement::SetValue(const nsAString& aValue)
SetFileName(aValue);
}
else {
SetValueInternal(aValue, nsnull);
SetValueInternal(aValue, nsnull, PR_FALSE);
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLInputElement::SetUserInput(const nsAString& aValue)
{
if (!nsContentUtils::IsCallerTrustedForWrite()) {
return NS_ERROR_DOM_SECURITY_ERR;
}
if (mType == NS_FORM_INPUT_FILE)
{
SetFileName(aValue);
} else {
SetValueInternal(aValue, nsnull, PR_TRUE);
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLInputElement::TakeTextFrameValue(const nsAString& aValue)
{
@ -883,7 +904,8 @@ nsHTMLInputElement::UpdateFileList()
nsresult
nsHTMLInputElement::SetValueInternal(const nsAString& aValue,
nsITextControlFrame* aFrame)
nsITextControlFrame* aFrame,
PRBool aUserInput)
{
NS_PRECONDITION(mType != NS_FORM_INPUT_FILE,
"Don't call SetValueInternal for file inputs");
@ -911,7 +933,8 @@ nsHTMLInputElement::SetValueInternal(const nsAString& aValue,
}
// If the frame owns the value, set the value in the frame
if (frameOwnsValue) {
formControlFrame->SetFormProperty(nsGkAtoms::value, aValue);
formControlFrame->SetFormProperty(
aUserInput ? nsGkAtoms::userInput : nsGkAtoms::value, aValue);
return NS_OK;
}
@ -1978,7 +2001,7 @@ nsHTMLInputElement::ParseAttribute(PRInt32 aNamespaceID,
// confuse values and filenames. However they're there for backwards
// compat.
SetFileName(EmptyString());
SetValueInternal(EmptyString(), nsnull);
SetValueInternal(EmptyString(), nsnull, PR_FALSE);
} else if (mType == NS_FORM_INPUT_FILE) {
SetFileName(EmptyString());
}
@ -2714,7 +2737,7 @@ nsHTMLInputElement::RestoreState(nsPresState* aState)
rv = aState->GetStateProperty(NS_LITERAL_STRING("v"), value);
NS_ASSERTION(NS_SUCCEEDED(rv), "value restore failed!");
if (rv == NS_STATE_PROPERTY_EXISTS) {
SetValueInternal(value, nsnull);
SetValueInternal(value, nsnull, PR_FALSE);
}
break;
}

View File

@ -74,6 +74,7 @@
#include "nsLayoutUtils.h"
#include "nsLayoutErrors.h"
#include "nsStubMutationObserver.h"
#include "nsDOMError.h"
static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
@ -109,7 +110,11 @@ public:
NS_DECL_NSIDOMNSHTMLTEXTAREAELEMENT
// nsIDOMNSEditableElement
NS_FORWARD_NSIDOMNSEDITABLEELEMENT(nsGenericHTMLElement::)
NS_IMETHOD GetEditor(nsIEditor** aEditor)
{
return nsGenericHTMLElement::GetEditor(aEditor);
}
NS_IMETHOD SetUserInput(const nsAString& aInput);
// nsIFormControl
NS_IMETHOD_(PRInt32) GetType() const { return NS_FORM_TEXTAREA; }
@ -198,7 +203,8 @@ protected:
void GetValueInternal(nsAString& aValue, PRBool aIgnoreWrap);
nsresult SetValueInternal(const nsAString& aValue,
nsITextControlFrame* aFrame);
nsITextControlFrame* aFrame,
PRBool aUserInput);
nsresult GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd);
/**
@ -479,7 +485,8 @@ nsHTMLTextAreaElement::TakeTextFrameValue(const nsAString& aValue)
nsresult
nsHTMLTextAreaElement::SetValueInternal(const nsAString& aValue,
nsITextControlFrame* aFrame)
nsITextControlFrame* aFrame,
PRBool aUserInput)
{
nsITextControlFrame* textControlFrame = aFrame;
nsIFormControlFrame* formControlFrame = textControlFrame;
@ -498,7 +505,8 @@ nsHTMLTextAreaElement::SetValueInternal(const nsAString& aValue,
textControlFrame->OwnsValue(&frameOwnsValue);
}
if (frameOwnsValue) {
formControlFrame->SetFormProperty(nsGkAtoms::value, aValue);
formControlFrame->SetFormProperty(
aUserInput ? nsGkAtoms::userInput : nsGkAtoms::value, aValue);
}
else {
if (mValue) {
@ -516,9 +524,18 @@ nsHTMLTextAreaElement::SetValueInternal(const nsAString& aValue,
NS_IMETHODIMP
nsHTMLTextAreaElement::SetValue(const nsAString& aValue)
{
return SetValueInternal(aValue, nsnull);
return SetValueInternal(aValue, nsnull, PR_FALSE);
}
NS_IMETHODIMP
nsHTMLTextAreaElement::SetUserInput(const nsAString& aValue)
{
if (!nsContentUtils::IsCallerTrustedForWrite()) {
return NS_ERROR_DOM_SECURITY_ERR;
}
SetValueInternal(aValue, nsnull, PR_TRUE);
return NS_OK;
}
NS_IMETHODIMP
nsHTMLTextAreaElement::SetValueChanged(PRBool aValueChanged)

View File

@ -79,6 +79,7 @@ _TEST_FILES = test_bug589.html \
test_bug332893-2.html \
test_bug332893-3.html \
test_bug332893-4.html \
test_bug388558.html \
test_bug332893-5.html \
test_bug332893-6.html \
test_bug353415-1.html \

View File

@ -0,0 +1,78 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=388558
-->
<head>
<title>Test for Bug 388558</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.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=388558">Mozilla Bug 388558</a>
<p id="display"></p>
<div id="content">
<input type="text" id="input" onchange="++inputChange;">
<textarea id="textarea" onchange="++textareaChange;"></textarea>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 388558 **/
var inputChange = 0;
var textareaChange = 0;
function testUserInput() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserWrite');
var input = document.getElementById("input");
var textarea = document.getElementById("textarea");
input.focus();
input.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).setUserInput("foo");
input.blur();
is(inputChange, 1, "Input element should have got one change event.");
input.focus();
input.value = "bar";
input.blur();
is(inputChange, 1,
"Change event dispatched when setting the value of the input element");
input.value = "";
is(inputChange, 1,
"Change event dispatched when setting the value of the input element (2).");
input.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).setUserInput("foo");
is(inputChange, 1,
"Change event dispatched when input element doesn't have focus.");
textarea.focus();
textarea.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).setUserInput("foo");
textarea.blur();
is(textareaChange, 1, "Textarea element should have got one change event.");
textarea.focus();
textarea.value = "bar";
textarea.blur();
is(textareaChange, 1,
"Change event dispatched when setting the value of the textarea element.");
textarea.value = "";
is(textareaChange, 1,
"Change event dispatched when setting the value of the textarea element (2).");
textarea.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).setUserInput("foo");
is(textareaChange, 1,
"Change event dispatched when textarea element doesn't have focus.");
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(testUserInput);
addLoadEvent(SimpleTest.finish);
</script>
</pre>
</body>
</html>

View File

@ -45,8 +45,13 @@ interface nsIEditor;
* such as HTML input and textarea.
*/
[scriptable, uuid(c4a71f8e-82ba-49d7-94f9-beb359361072)]
[scriptable, uuid(b33eb56c-3120-418c-892b-774b00c7dde8)]
interface nsIDOMNSEditableElement : nsISupports
{
readonly attribute nsIEditor editor;
// This is similar to set .value on nsIDOMInput/TextAreaElements, but
// handling of the value change is closer to the normal user input, so
// 'change' event for example will be dispatched when focusing out the
// element.
void setUserInput(in DOMString input);
};

View File

@ -1942,15 +1942,22 @@ nsresult nsTextControlFrame::SetFormProperty(nsIAtom* aName, const nsAString& aV
if (!mIsProcessing)//some kind of lock.
{
mIsProcessing = PR_TRUE;
if (nsGkAtoms::value == aName)
PRBool isUserInput = (nsGkAtoms::userInput == aName);
if (nsGkAtoms::value == aName || isUserInput)
{
PRBool fireChangeEvent = GetFireChangeEventState();
if (isUserInput) {
SetFireChangeEventState(PR_TRUE);
}
if (mEditor && mUseEditor) {
// If the editor exists, the control needs to be informed that the value
// has changed.
SetValueChanged(PR_TRUE);
}
nsresult rv = SetValue(aValue); // set new text value
if (isUserInput) {
SetFireChangeEventState(fireChangeEvent);
}
NS_ENSURE_SUCCESS(rv, rv);
}
else if (nsGkAtoms::select == aName)

View File

@ -74,6 +74,7 @@
#include "nsIGenericFactory.h"
#include "nsToolkitCompsCID.h"
#include "nsEmbedCID.h"
#include "nsIDOMNSEditableElement.h"
NS_INTERFACE_MAP_BEGIN(nsFormFillController)
NS_INTERFACE_MAP_ENTRY(nsIFormFillController)
@ -397,9 +398,10 @@ nsFormFillController::GetTextValue(nsAString & aTextValue)
NS_IMETHODIMP
nsFormFillController::SetTextValue(const nsAString & aTextValue)
{
if (mFocusedInput) {
nsCOMPtr<nsIDOMNSEditableElement> editable = do_QueryInterface(mFocusedInput);
if (editable) {
mSuppressOnInput = PR_TRUE;
mFocusedInput->SetValue(aTextValue);
editable->SetUserInput(aTextValue);
mSuppressOnInput = PR_FALSE;
}
return NS_OK;