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
if (checked() == nowChecked)
return;
RefPtr<HTMLInputElement> protector(this);
m_reflectsCheckedAttribute = false;
m_isChecked = nowChecked;
setNeedsStyleRecalc(SubtreeStyleChange);
......@@ -882,6 +883,8 @@ void HTMLInputElement::setChecked(bool nowChecked, TextFieldEventBehavior eventB
// definitely wrong in practice for these types of elements.
if (eventBehavior != DispatchNoEvent && inDocument() && m_inputType->shouldSendChangeEventAfterCheckedChanged()) {
setTextAsOfLastFormControlChangeEvent(String());
if (eventBehavior == DispatchInputAndChangeEvent)
dispatchFormControlInputEvent();
dispatchFormControlChangeEvent();
}
......
......@@ -236,28 +236,33 @@ String HTMLSelectElement::value() const
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.
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;
for (unsigned i = 0; i < items.size(); i++) {
if (isHTMLOptionElement(items[i])) {
if (toHTMLOptionElement(items[i])->value() == value) {
setSelectedIndex(optionIndex);
return;
if (value.isNull()) {
optionIndex = -1;
} else {
// Find the option with value() matching the given parameter and make it the current selection.
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
......@@ -678,12 +683,12 @@ void HTMLSelectElement::listBoxOnChange()
}
}
void HTMLSelectElement::dispatchInputAndChangeEventForMenuList()
void HTMLSelectElement::dispatchInputAndChangeEventForMenuList(bool requiresUserGesture)
{
ASSERT(usesMenuList());
int selected = selectedIndex();
if (m_lastOnChangeIndex != selected && m_isProcessingUserDrivenChange) {
if (m_lastOnChangeIndex != selected && (!requiresUserGesture || m_isProcessingUserDrivenChange)) {
m_lastOnChangeIndex = selected;
m_isProcessingUserDrivenChange = false;
RefPtr<HTMLSelectElement> protector(this);
......
......@@ -69,7 +69,7 @@ public:
void remove(int index);
String value() const;
void setValue(const String&);
void setValue(const String&, bool sendEvents = false);
String suggestedValue() const;
void setSuggestedValue(const String&);
......@@ -145,7 +145,7 @@ private:
virtual void defaultEventHandler(Event*) OVERRIDE;
void dispatchInputAndChangeEventForMenuList();
void dispatchInputAndChangeEventForMenuList(bool requiresUserGesture = true);
void recalcListItems(bool updateSelectedStates = true) const;
......
......@@ -336,21 +336,22 @@ String HTMLTextAreaElement::value() const
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;
setNeedsValidityCheck();
}
void HTMLTextAreaElement::setNonDirtyValue(const String& value)
{
setValueCommon(value);
setValueCommon(value, DispatchNoEvent);
m_isDirty = false;
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.
// We normalize line endings coming from JavaScript here.
......@@ -365,7 +366,8 @@ void HTMLTextAreaElement::setValueCommon(const String& newValue)
m_value = normalizedValue;
setInnerTextValue(m_value);
setLastChangeWasNotUserEdit();
if (eventBehavior == DispatchNoEvent)
setLastChangeWasNotUserEdit();
updatePlaceholderVisibility(false);
setNeedsStyleRecalc(SubtreeStyleChange);
setFormControlValueMatchesRenderer(true);
......@@ -378,7 +380,13 @@ void HTMLTextAreaElement::setValueCommon(const String& newValue)
}
notifyFormStateChanged();
setTextAsOfLastFormControlChangeEvent(normalizedValue);
if (eventBehavior == DispatchNoEvent) {
setTextAsOfLastFormControlChangeEvent(normalizedValue);
} else {
if (eventBehavior == DispatchInputAndChangeEvent)
dispatchFormControlInputEvent();
dispatchFormControlChangeEvent();
}
}
String HTMLTextAreaElement::defaultValue() const
......
......@@ -42,7 +42,7 @@ public:
bool shouldWrapText() const { return m_wrap != NoWrap; }
virtual String value() const OVERRIDE;
void setValue(const String&);
void setValue(const String&, TextFieldEventBehavior = DispatchNoEvent);
String defaultValue() const;
void setDefaultValue(const String&);
int textLength() const { return value().length(); }
......@@ -75,7 +75,7 @@ private:
static String sanitizeUserInputValue(const String&, unsigned maxLength);
void updateValue() const;
void setNonDirtyValue(const String&);
void setValueCommon(const String&);
void setValueCommon(const String&, TextFieldEventBehavior);
virtual bool supportsPlaceholder() const OVERRIDE { return true; }
virtual void updatePlaceholderText() OVERRIDE;
......
......@@ -92,14 +92,14 @@ bool WebFormControlElement::autoComplete() const
return false;
}
void WebFormControlElement::setValue(const WebString& value, bool sendChangeEvent)
void WebFormControlElement::setValue(const WebString& value, bool sendEvents)
{
if (isHTMLInputElement(*m_private))
unwrap<HTMLInputElement>()->setValue(value, sendChangeEvent ? DispatchChangeEvent : DispatchNoEvent);
if (isHTMLTextAreaElement(*m_private))
unwrap<HTMLTextAreaElement>()->setValue(value);
if (isHTMLSelectElement(*m_private))
unwrap<HTMLSelectElement>()->setValue(value);
unwrap<HTMLInputElement>()->setValue(value, sendEvents ? DispatchInputAndChangeEvent : DispatchNoEvent);
else if (isHTMLTextAreaElement(*m_private))
unwrap<HTMLTextAreaElement>()->setValue(value, sendEvents ? DispatchInputAndChangeEvent : DispatchNoEvent);
else if (isHTMLSelectElement(*m_private))
unwrap<HTMLSelectElement>()->setValue(value, sendEvents);
}
WebString WebFormControlElement::value() const
......@@ -117,9 +117,9 @@ void WebFormControlElement::setSuggestedValue(const WebString& value)
{
if (isHTMLInputElement(*m_private))
unwrap<HTMLInputElement>()->setSuggestedValue(value);
if (isHTMLTextAreaElement(*m_private))
else if (isHTMLTextAreaElement(*m_private))
unwrap<HTMLTextAreaElement>()->setSuggestedValue(value);
if (isHTMLSelectElement(*m_private))
else if (isHTMLSelectElement(*m_private))
unwrap<HTMLSelectElement>()->setSuggestedValue(value);
}
......@@ -147,7 +147,7 @@ void WebFormControlElement::setSelectionRange(int start, int end)
{
if (isHTMLInputElement(*m_private))
unwrap<HTMLInputElement>()->setSelectionRange(start, end);
if (isHTMLTextAreaElement(*m_private))
else if (isHTMLTextAreaElement(*m_private))
unwrap<HTMLTextAreaElement>()->setSelectionRange(start, end);
}
......
......@@ -107,9 +107,9 @@ bool WebInputElement::isValidValue(const WebString& value) const
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
......
......@@ -59,6 +59,7 @@ public:
BLINK_EXPORT WebString formControlName() const;
BLINK_EXPORT WebString formControlType() const;
// FIXME: remove this method when no longer used.
BLINK_EXPORT void dispatchFormControlChangeEvent();
BLINK_EXPORT bool isAutofilled() const;
......@@ -70,7 +71,7 @@ public:
// 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
// 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
// the selected option if present. If no selected option, an empty string
// is returned. If element doesn't fall into input element, textarea element
......
......@@ -73,7 +73,7 @@ namespace blink {
BLINK_EXPORT bool isActivatedSubmit() const;
BLINK_EXPORT void setActivatedSubmit(bool);
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.
// Can't be used if a renderer doesn't exist or on a non text field type.
// 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