For input and textarea fields send these events:
Focus
KeyDown
Change (already present)
Input (already present)
KeyUp
Blur
For select fields send these events:
Focus
Change (already present)
Input (already present)
Blur
BUG=581537
TEST=AutofillInteractiveTest
Review-Url: https://codereview.chromium.org/1955963002
Cr-Commit-Position: refs/heads/master@{#392842}
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc
index 045f6924..5775936 100644
--- a/chrome/browser/autofill/autofill_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -103,6 +103,66 @@
"<input type=\"submit\" value=\"Submit\">"
"</form>";
+// TODO(crbug.com/609861): Remove the autocomplete attribute from the textarea
+// field when the bug is fixed.
+static const char kTestEventFormString[] =
+ "<script type=\"text/javascript\">"
+ "var inputfocus = false;"
+ "var inputkeydown = false;"
+ "var inputinput = false;"
+ "var inputchange = false;"
+ "var inputkeyup = false;"
+ "var inputblur = false;"
+ "var textfocus = false;"
+ "var textkeydown = false;"
+ "var textinput= false;"
+ "var textchange = false;"
+ "var textkeyup = false;"
+ "var textblur = false;"
+ "var selectfocus = false;"
+ "var selectinput = false;"
+ "var selectchange = false;"
+ "var selectblur = false;"
+ "</script>"
+ "<form action=\"http://www.example.com/\" method=\"POST\">"
+ "<label for=\"firstname\">First name:</label>"
+ " <input type=\"text\" id=\"firstname\""
+ " onfocus=\"domAutomationController.send(true)\"><br>"
+ "<label for=\"lastname\">Last name:</label>"
+ " <input type=\"text\" id=\"lastname\""
+ " onfocus=\"inputfocus = true\" onkeydown=\"inputkeydown = true\""
+ " oninput=\"inputinput = true\" onchange=\"inputchange = true\""
+ " onkeyup=\"inputkeyup = true\" onblur=\"inputblur = true\" ><br>"
+ "<label for=\"address1\">Address line 1:</label>"
+ " <input type=\"text\" id=\"address1\"><br>"
+ "<label for=\"address2\">Address line 2:</label>"
+ " <input type=\"text\" id=\"address2\"><br>"
+ "<label for=\"city\">City:</label>"
+ " <textarea rows=\"4\" cols=\"50\" id=\"city\" name=\"city\""
+ " autocomplete=\"address-level2\" onfocus=\"textfocus = true\""
+ " onkeydown=\"textkeydown = true\" oninput=\"textinput = true\""
+ " onchange=\"textchange = true\" onkeyup=\"textkeyup = true\""
+ " onblur=\"textblur = true\"></textarea><br>"
+ "<label for=\"state\">State:</label>"
+ " <select id=\"state\""
+ " onfocus=\"selectfocus = true\" oninput=\"selectinput = true\""
+ " onchange=\"selectchange = true\" onblur=\"selectblur = true\" >"
+ " <option value=\"\" selected=\"yes\">--</option>"
+ " <option value=\"CA\">California</option>"
+ " <option value=\"TX\">Texas</option>"
+ " </select><br>"
+ "<label for=\"zip\">ZIP code:</label>"
+ " <input type=\"text\" id=\"zip\"><br>"
+ "<label for=\"country\">Country:</label>"
+ " <select id=\"country\">"
+ " <option value=\"\" selected=\"yes\">--</option>"
+ " <option value=\"CA\">Canada</option>"
+ " <option value=\"US\">United States</option>"
+ " </select><br>"
+ "<label for=\"phone\">Phone number:</label>"
+ " <input type=\"text\" id=\"phone\"><br>"
+ "</form>";
+
// AutofillManagerTestDelegateImpl --------------------------------------------
class AutofillManagerTestDelegateImpl
@@ -1180,6 +1240,105 @@
TryBasicFormFill();
}
+// Test that filling a form sends all the expected events to the different
+// fields being filled.
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest, AutofillEvents) {
+ CreateTestProfile();
+
+ // Load the test page.
+ ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+ browser(), GURL(std::string(kDataURIPrefix) + kTestEventFormString)));
+
+ // Invoke Autofill.
+ TryBasicFormFill();
+
+ // Checks that all the events were fired for the input field.
+ bool input_focus_triggered;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetRenderViewHost(), "domAutomationController.send(inputfocus);",
+ &input_focus_triggered));
+ EXPECT_TRUE(input_focus_triggered);
+ bool input_keydown_triggered;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetRenderViewHost(), "domAutomationController.send(inputkeydown);",
+ &input_keydown_triggered));
+ EXPECT_TRUE(input_keydown_triggered);
+ bool input_input_triggered;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetRenderViewHost(), "domAutomationController.send(inputinput);",
+ &input_input_triggered));
+ EXPECT_TRUE(input_input_triggered);
+ bool input_change_triggered;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetRenderViewHost(), "domAutomationController.send(inputchange);",
+ &input_change_triggered));
+ EXPECT_TRUE(input_change_triggered);
+ bool input_keyup_triggered;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetRenderViewHost(), "domAutomationController.send(inputkeyup);",
+ &input_keyup_triggered));
+ EXPECT_TRUE(input_keyup_triggered);
+ bool input_blur_triggered;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetRenderViewHost(), "domAutomationController.send(inputblur);",
+ &input_blur_triggered));
+ EXPECT_TRUE(input_blur_triggered);
+
+ // Checks that all the events were fired for the textarea field.
+ bool text_focus_triggered;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetRenderViewHost(), "domAutomationController.send(textfocus);",
+ &text_focus_triggered));
+ EXPECT_TRUE(text_focus_triggered);
+ bool text_keydown_triggered;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetRenderViewHost(), "domAutomationController.send(textkeydown);",
+ &text_keydown_triggered));
+ EXPECT_TRUE(text_keydown_triggered);
+ bool text_input_triggered;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetRenderViewHost(), "domAutomationController.send(textinput);",
+ &text_input_triggered));
+ EXPECT_TRUE(text_input_triggered);
+ bool text_change_triggered;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetRenderViewHost(), "domAutomationController.send(textchange);",
+ &text_change_triggered));
+ EXPECT_TRUE(text_change_triggered);
+ bool text_keyup_triggered;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetRenderViewHost(), "domAutomationController.send(textkeyup);",
+ &text_keyup_triggered));
+ EXPECT_TRUE(text_keyup_triggered);
+ bool text_blur_triggered;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetRenderViewHost(), "domAutomationController.send(textblur);",
+ &text_blur_triggered));
+ EXPECT_TRUE(text_blur_triggered);
+
+ // Checks that all the events were fired for the select field.
+ bool select_focus_triggered;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetRenderViewHost(), "domAutomationController.send(selectfocus);",
+ &select_focus_triggered));
+ EXPECT_TRUE(select_focus_triggered);
+ bool select_input_triggered;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetRenderViewHost(), "domAutomationController.send(selectinput);",
+ &select_input_triggered));
+ EXPECT_TRUE(select_input_triggered);
+ bool select_change_triggered;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetRenderViewHost(), "domAutomationController.send(selectchange);",
+ &select_change_triggered));
+ EXPECT_TRUE(select_change_triggered);
+ bool select_blur_triggered;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetRenderViewHost(), "domAutomationController.send(selectblur);",
+ &select_blur_triggered));
+ EXPECT_TRUE(select_blur_triggered);
+}
+
// Test fails on Linux ASAN, see http://crbug.com/532737
#if defined(ADDRESS_SANITIZER)
#define MAYBE_AutofillAfterTranslate DISABLED_AutofillAfterTranslate
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc
index 6b48f2d45..6fa43b2 100644
--- a/components/autofill/content/renderer/form_autofill_util.cc
+++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -890,7 +890,7 @@
// returns the default maxlength value.
TruncateString(&value, input_element->maxLength());
}
- field->setValue(value, true);
+ field->setAutofillValue(value);
}
// Setting the form might trigger JavaScript, which is capable of
// destroying the frame.
diff --git a/third_party/WebKit/Source/web/WebFormControlElement.cpp b/third_party/WebKit/Source/web/WebFormControlElement.cpp
index 7dbbea5..64f0c9d 100644
--- a/third_party/WebKit/Source/web/WebFormControlElement.cpp
+++ b/third_party/WebKit/Source/web/WebFormControlElement.cpp
@@ -97,6 +97,26 @@
unwrap<HTMLSelectElement>()->setValue(value, sendEvents);
}
+void WebFormControlElement::setAutofillValue(const WebString& value)
+{
+ // The input and change events will be sent in setValue.
+ if (isHTMLInputElement(*m_private) || isHTMLTextAreaElement(*m_private)) {
+ if (!focused())
+ unwrap<Element>()->dispatchFocusEvent(nullptr, WebFocusTypeForward, nullptr);
+ unwrap<Element>()->dispatchScopedEvent(Event::createBubble(EventTypeNames::keydown));
+ unwrap<HTMLTextFormControlElement>()->setValue(value, DispatchInputAndChangeEvent);
+ unwrap<Element>()->dispatchScopedEvent(Event::createBubble(EventTypeNames::keyup));
+ if (!focused())
+ unwrap<Element>()->dispatchBlurEvent(nullptr, WebFocusTypeForward, nullptr);
+ } else if (isHTMLSelectElement(*m_private)) {
+ if (!focused())
+ unwrap<Element>()->dispatchFocusEvent(nullptr, WebFocusTypeForward, nullptr);
+ unwrap<HTMLSelectElement>()->setValue(value, true);
+ if (!focused())
+ unwrap<Element>()->dispatchBlurEvent(nullptr, WebFocusTypeForward, nullptr);
+ }
+}
+
WebString WebFormControlElement::value() const
{
if (isHTMLInputElement(*m_private))
diff --git a/third_party/WebKit/public/web/WebFormControlElement.h b/third_party/WebKit/public/web/WebFormControlElement.h
index 504f64fe..0f01e1b 100644
--- a/third_party/WebKit/public/web/WebFormControlElement.h
+++ b/third_party/WebKit/public/web/WebFormControlElement.h
@@ -67,6 +67,9 @@
// 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 sendEvents = false);
+ // Sets the autofilled value for input element, textarea element and select
+ // element and sends a sequence of events to the element.
+ BLINK_EXPORT void setAutofillValue(const WebString&);
// 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