Commit 21d9f621 authored by dbeam@chromium.org's avatar dbeam@chromium.org

Autofill/rAc: dispatch "input" events when changing text contents of <textarea>,

<select>, or <input> tags via Autofill.

This more closely matches the spec behavior as "input" events should be fired
whenever the text is changed.  From the spec[1]:

"""
When the user agent is to change an input element's value on behalf of the user
(e.g. as part of a form prefilling feature), the user agent must queue a task to
first update the value accordingly, then fire a simple event that bubbles named
input at the input element, then fire a simple event that bubbles named change
at the input element.
"""

BUG=353691
R=tkent@chromium.org

[1] http://www.whatwg.org/specs/web-apps/current-work/multipage/common-input-element-attributes.html#event-input-input

Review URL: https://codereview.chromium.org/215903003

git-svn-id: svn://svn.chromium.org/blink/trunk@170278 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 7ea51c5c
...@@ -856,6 +856,7 @@ void HTMLInputElement::setChecked(bool nowChecked, TextFieldEventBehavior eventB ...@@ -856,6 +856,7 @@ void HTMLInputElement::setChecked(bool nowChecked, TextFieldEventBehavior eventB
if (checked() == nowChecked) if (checked() == nowChecked)
return; return;
RefPtr<HTMLInputElement> protector(this);
m_reflectsCheckedAttribute = false; m_reflectsCheckedAttribute = false;
m_isChecked = nowChecked; m_isChecked = nowChecked;
setNeedsStyleRecalc(SubtreeStyleChange); setNeedsStyleRecalc(SubtreeStyleChange);
...@@ -882,6 +883,8 @@ void HTMLInputElement::setChecked(bool nowChecked, TextFieldEventBehavior eventB ...@@ -882,6 +883,8 @@ void HTMLInputElement::setChecked(bool nowChecked, TextFieldEventBehavior eventB
// definitely wrong in practice for these types of elements. // definitely wrong in practice for these types of elements.
if (eventBehavior != DispatchNoEvent && inDocument() && m_inputType->shouldSendChangeEventAfterCheckedChanged()) { if (eventBehavior != DispatchNoEvent && inDocument() && m_inputType->shouldSendChangeEventAfterCheckedChanged()) {
setTextAsOfLastFormControlChangeEvent(String()); setTextAsOfLastFormControlChangeEvent(String());
if (eventBehavior == DispatchInputAndChangeEvent)
dispatchFormControlInputEvent();
dispatchFormControlChangeEvent(); dispatchFormControlChangeEvent();
} }
......
...@@ -236,28 +236,33 @@ String HTMLSelectElement::value() const ...@@ -236,28 +236,33 @@ String HTMLSelectElement::value() const
return ""; return "";
} }
void HTMLSelectElement::setValue(const String &value) void HTMLSelectElement::setValue(const String &value, bool sendEvents)
{ {
// We clear the previously selected option(s) when needed, to guarantee calling setSelectedIndex() only once. // We clear the previously selected option(s) when needed, to guarantee calling setSelectedIndex() only once.
if (value.isNull()) {
setSelectedIndex(-1);
return;
}
// Find the option with value() matching the given parameter and make it the current selection.
const Vector<HTMLElement*>& items = listItems();
unsigned optionIndex = 0; unsigned optionIndex = 0;
for (unsigned i = 0; i < items.size(); i++) { if (value.isNull()) {
if (isHTMLOptionElement(items[i])) { optionIndex = -1;
if (toHTMLOptionElement(items[i])->value() == value) { } else {
setSelectedIndex(optionIndex); // Find the option with value() matching the given parameter and make it the current selection.
return; const Vector<HTMLElement*>& items = listItems();
for (unsigned i = 0; i < items.size(); i++) {
if (isHTMLOptionElement(items[i])) {
if (toHTMLOptionElement(items[i])->value() == value)
break;
optionIndex++;
} }
optionIndex++;
} }
if (optionIndex >= items.size())
optionIndex = -1;
} }
setSelectedIndex(optionIndex);
setSelectedIndex(-1); if (sendEvents) {
if (usesMenuList())
dispatchInputAndChangeEventForMenuList(false);
else
listBoxOnChange();
}
} }
String HTMLSelectElement::suggestedValue() const String HTMLSelectElement::suggestedValue() const
...@@ -678,12 +683,12 @@ void HTMLSelectElement::listBoxOnChange() ...@@ -678,12 +683,12 @@ void HTMLSelectElement::listBoxOnChange()
} }
} }
void HTMLSelectElement::dispatchInputAndChangeEventForMenuList() void HTMLSelectElement::dispatchInputAndChangeEventForMenuList(bool requiresUserGesture)
{ {
ASSERT(usesMenuList()); ASSERT(usesMenuList());
int selected = selectedIndex(); int selected = selectedIndex();
if (m_lastOnChangeIndex != selected && m_isProcessingUserDrivenChange) { if (m_lastOnChangeIndex != selected && (!requiresUserGesture || m_isProcessingUserDrivenChange)) {
m_lastOnChangeIndex = selected; m_lastOnChangeIndex = selected;
m_isProcessingUserDrivenChange = false; m_isProcessingUserDrivenChange = false;
RefPtr<HTMLSelectElement> protector(this); RefPtr<HTMLSelectElement> protector(this);
......
...@@ -69,7 +69,7 @@ public: ...@@ -69,7 +69,7 @@ public:
void remove(int index); void remove(int index);
String value() const; String value() const;
void setValue(const String&); void setValue(const String&, bool sendEvents = false);
String suggestedValue() const; String suggestedValue() const;
void setSuggestedValue(const String&); void setSuggestedValue(const String&);
...@@ -145,7 +145,7 @@ private: ...@@ -145,7 +145,7 @@ private:
virtual void defaultEventHandler(Event*) OVERRIDE; virtual void defaultEventHandler(Event*) OVERRIDE;
void dispatchInputAndChangeEventForMenuList(); void dispatchInputAndChangeEventForMenuList(bool requiresUserGesture = true);
void recalcListItems(bool updateSelectedStates = true) const; void recalcListItems(bool updateSelectedStates = true) const;
......
...@@ -336,21 +336,22 @@ String HTMLTextAreaElement::value() const ...@@ -336,21 +336,22 @@ String HTMLTextAreaElement::value() const
return m_value; return m_value;
} }
void HTMLTextAreaElement::setValue(const String& value) void HTMLTextAreaElement::setValue(const String& value, TextFieldEventBehavior eventBehavior)
{ {
setValueCommon(value); RefPtr<HTMLTextAreaElement> protector(this);
setValueCommon(value, eventBehavior);
m_isDirty = true; m_isDirty = true;
setNeedsValidityCheck(); setNeedsValidityCheck();
} }
void HTMLTextAreaElement::setNonDirtyValue(const String& value) void HTMLTextAreaElement::setNonDirtyValue(const String& value)
{ {
setValueCommon(value); setValueCommon(value, DispatchNoEvent);
m_isDirty = false; m_isDirty = false;
setNeedsValidityCheck(); setNeedsValidityCheck();
} }
void HTMLTextAreaElement::setValueCommon(const String& newValue) void HTMLTextAreaElement::setValueCommon(const String& newValue, TextFieldEventBehavior eventBehavior)
{ {
// Code elsewhere normalizes line endings added by the user via the keyboard or pasting. // Code elsewhere normalizes line endings added by the user via the keyboard or pasting.
// We normalize line endings coming from JavaScript here. // We normalize line endings coming from JavaScript here.
...@@ -365,7 +366,8 @@ void HTMLTextAreaElement::setValueCommon(const String& newValue) ...@@ -365,7 +366,8 @@ void HTMLTextAreaElement::setValueCommon(const String& newValue)
m_value = normalizedValue; m_value = normalizedValue;
setInnerTextValue(m_value); setInnerTextValue(m_value);
setLastChangeWasNotUserEdit(); if (eventBehavior == DispatchNoEvent)
setLastChangeWasNotUserEdit();
updatePlaceholderVisibility(false); updatePlaceholderVisibility(false);
setNeedsStyleRecalc(SubtreeStyleChange); setNeedsStyleRecalc(SubtreeStyleChange);
setFormControlValueMatchesRenderer(true); setFormControlValueMatchesRenderer(true);
...@@ -378,7 +380,13 @@ void HTMLTextAreaElement::setValueCommon(const String& newValue) ...@@ -378,7 +380,13 @@ void HTMLTextAreaElement::setValueCommon(const String& newValue)
} }
notifyFormStateChanged(); notifyFormStateChanged();
setTextAsOfLastFormControlChangeEvent(normalizedValue); if (eventBehavior == DispatchNoEvent) {
setTextAsOfLastFormControlChangeEvent(normalizedValue);
} else {
if (eventBehavior == DispatchInputAndChangeEvent)
dispatchFormControlInputEvent();
dispatchFormControlChangeEvent();
}
} }
String HTMLTextAreaElement::defaultValue() const String HTMLTextAreaElement::defaultValue() const
......
...@@ -42,7 +42,7 @@ public: ...@@ -42,7 +42,7 @@ public:
bool shouldWrapText() const { return m_wrap != NoWrap; } bool shouldWrapText() const { return m_wrap != NoWrap; }
virtual String value() const OVERRIDE; virtual String value() const OVERRIDE;
void setValue(const String&); void setValue(const String&, TextFieldEventBehavior = DispatchNoEvent);
String defaultValue() const; String defaultValue() const;
void setDefaultValue(const String&); void setDefaultValue(const String&);
int textLength() const { return value().length(); } int textLength() const { return value().length(); }
...@@ -75,7 +75,7 @@ private: ...@@ -75,7 +75,7 @@ private:
static String sanitizeUserInputValue(const String&, unsigned maxLength); static String sanitizeUserInputValue(const String&, unsigned maxLength);
void updateValue() const; void updateValue() const;
void setNonDirtyValue(const String&); void setNonDirtyValue(const String&);
void setValueCommon(const String&); void setValueCommon(const String&, TextFieldEventBehavior);
virtual bool supportsPlaceholder() const OVERRIDE { return true; } virtual bool supportsPlaceholder() const OVERRIDE { return true; }
virtual void updatePlaceholderText() OVERRIDE; virtual void updatePlaceholderText() OVERRIDE;
......
...@@ -92,14 +92,14 @@ bool WebFormControlElement::autoComplete() const ...@@ -92,14 +92,14 @@ bool WebFormControlElement::autoComplete() const
return false; return false;
} }
void WebFormControlElement::setValue(const WebString& value, bool sendChangeEvent) void WebFormControlElement::setValue(const WebString& value, bool sendEvents)
{ {
if (isHTMLInputElement(*m_private)) if (isHTMLInputElement(*m_private))
unwrap<HTMLInputElement>()->setValue(value, sendChangeEvent ? DispatchChangeEvent : DispatchNoEvent); unwrap<HTMLInputElement>()->setValue(value, sendEvents ? DispatchInputAndChangeEvent : DispatchNoEvent);
if (isHTMLTextAreaElement(*m_private)) else if (isHTMLTextAreaElement(*m_private))
unwrap<HTMLTextAreaElement>()->setValue(value); unwrap<HTMLTextAreaElement>()->setValue(value, sendEvents ? DispatchInputAndChangeEvent : DispatchNoEvent);
if (isHTMLSelectElement(*m_private)) else if (isHTMLSelectElement(*m_private))
unwrap<HTMLSelectElement>()->setValue(value); unwrap<HTMLSelectElement>()->setValue(value, sendEvents);
} }
WebString WebFormControlElement::value() const WebString WebFormControlElement::value() const
...@@ -117,9 +117,9 @@ void WebFormControlElement::setSuggestedValue(const WebString& value) ...@@ -117,9 +117,9 @@ void WebFormControlElement::setSuggestedValue(const WebString& value)
{ {
if (isHTMLInputElement(*m_private)) if (isHTMLInputElement(*m_private))
unwrap<HTMLInputElement>()->setSuggestedValue(value); unwrap<HTMLInputElement>()->setSuggestedValue(value);
if (isHTMLTextAreaElement(*m_private)) else if (isHTMLTextAreaElement(*m_private))
unwrap<HTMLTextAreaElement>()->setSuggestedValue(value); unwrap<HTMLTextAreaElement>()->setSuggestedValue(value);
if (isHTMLSelectElement(*m_private)) else if (isHTMLSelectElement(*m_private))
unwrap<HTMLSelectElement>()->setSuggestedValue(value); unwrap<HTMLSelectElement>()->setSuggestedValue(value);
} }
...@@ -147,7 +147,7 @@ void WebFormControlElement::setSelectionRange(int start, int end) ...@@ -147,7 +147,7 @@ void WebFormControlElement::setSelectionRange(int start, int end)
{ {
if (isHTMLInputElement(*m_private)) if (isHTMLInputElement(*m_private))
unwrap<HTMLInputElement>()->setSelectionRange(start, end); unwrap<HTMLInputElement>()->setSelectionRange(start, end);
if (isHTMLTextAreaElement(*m_private)) else if (isHTMLTextAreaElement(*m_private))
unwrap<HTMLTextAreaElement>()->setSelectionRange(start, end); unwrap<HTMLTextAreaElement>()->setSelectionRange(start, end);
} }
......
...@@ -107,9 +107,9 @@ bool WebInputElement::isValidValue(const WebString& value) const ...@@ -107,9 +107,9 @@ bool WebInputElement::isValidValue(const WebString& value) const
return constUnwrap<HTMLInputElement>()->isValidValue(value); return constUnwrap<HTMLInputElement>()->isValidValue(value);
} }
void WebInputElement::setChecked(bool nowChecked, bool sendChangeEvent) void WebInputElement::setChecked(bool nowChecked, bool sendEvents)
{ {
unwrap<HTMLInputElement>()->setChecked(nowChecked, sendChangeEvent ? DispatchChangeEvent : DispatchNoEvent); unwrap<HTMLInputElement>()->setChecked(nowChecked, sendEvents ? DispatchInputAndChangeEvent : DispatchNoEvent);
} }
bool WebInputElement::isChecked() const bool WebInputElement::isChecked() const
......
...@@ -59,6 +59,7 @@ public: ...@@ -59,6 +59,7 @@ public:
BLINK_EXPORT WebString formControlName() const; BLINK_EXPORT WebString formControlName() const;
BLINK_EXPORT WebString formControlType() const; BLINK_EXPORT WebString formControlType() const;
// FIXME: remove this method when no longer used.
BLINK_EXPORT void dispatchFormControlChangeEvent(); BLINK_EXPORT void dispatchFormControlChangeEvent();
BLINK_EXPORT bool isAutofilled() const; BLINK_EXPORT bool isAutofilled() const;
...@@ -70,7 +71,7 @@ public: ...@@ -70,7 +71,7 @@ public:
// Sets value for input element, textarea element and select element. For select // Sets value for input element, textarea element and select element. For select
// element it finds the option with value matches the given parameter and make the // element it finds the option with value matches the given parameter and make the
// option as the current selection. // option as the current selection.
BLINK_EXPORT void setValue(const WebString&, bool sendChangeEvent = false); BLINK_EXPORT void setValue(const WebString&, bool sendEvents = false);
// Returns value of element. For select element, it returns the value of // Returns value of element. For select element, it returns the value of
// the selected option if present. If no selected option, an empty string // the selected option if present. If no selected option, an empty string
// is returned. If element doesn't fall into input element, textarea element // is returned. If element doesn't fall into input element, textarea element
......
...@@ -73,7 +73,7 @@ namespace blink { ...@@ -73,7 +73,7 @@ namespace blink {
BLINK_EXPORT bool isActivatedSubmit() const; BLINK_EXPORT bool isActivatedSubmit() const;
BLINK_EXPORT void setActivatedSubmit(bool); BLINK_EXPORT void setActivatedSubmit(bool);
BLINK_EXPORT int size() const; BLINK_EXPORT int size() const;
BLINK_EXPORT void setChecked(bool, bool sendChangeEvent = false); BLINK_EXPORT void setChecked(bool, bool sendEvents = false);
// Sets the value inside the text field without being sanitized. // Sets the value inside the text field without being sanitized.
// Can't be used if a renderer doesn't exist or on a non text field type. // Can't be used if a renderer doesn't exist or on a non text field type.
// Caret will be moved to the end. // Caret will be moved to the end.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment