summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordhollowa@chromium.org <dhollowa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-03 20:52:28 +0000
committerdhollowa@chromium.org <dhollowa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-03 20:52:28 +0000
commita1107c5d54db86a52e2aa04ed090112e569442ae (patch)
tree1610a68124ff3a9375619a0c381975c20d8cebfc
parent93120fea1fb7a895ef0469bb95540aa39520c691 (diff)
downloadchromium_src-a1107c5d54db86a52e2aa04ed090112e569442ae.zip
chromium_src-a1107c5d54db86a52e2aa04ed090112e569442ae.tar.gz
chromium_src-a1107c5d54db86a52e2aa04ed090112e569442ae.tar.bz2
Support autocompletion for HTMl5 tags:"email", "month" and "tel".
BUG=65654 TEST=1.make HTML5 forms with the following input types: - Email input: <input type="email"> - Date picker: <input type="month"> for credit card expiration. - Telephone input: <input type="tel"> - Placeholder text: <input name="address" placeholder="1 Main Street"/> 2.Try to fill. Implement tests for email, month and tel input type. Also this patch needs WebKit patch, please refer to https://bugs.webkit.org/show_bug.cgi?id=51809 Actually, original issue item says placeholder problem, but I cannot reproduce manually. Review URL: http://codereview.chromium.org/6033010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@73660 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/autofill/autofill_manager.cc16
-rw-r--r--chrome/browser/autofill/autofill_manager.h5
-rw-r--r--chrome/browser/autofill/autofill_manager_unittest.cc212
-rw-r--r--chrome/browser/autofill/credit_card.cc23
-rw-r--r--chrome/browser/autofill/credit_card.h3
-rw-r--r--chrome/browser/autofill/credit_card_field.cc60
-rw-r--r--chrome/browser/autofill/personal_data_manager.cc9
-rw-r--r--chrome/renderer/autofill/form_manager.cc116
-rw-r--r--chrome/renderer/autofill/form_manager_browsertest.cc51
9 files changed, 377 insertions, 118 deletions
diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc
index 84af836..adad24b 100644
--- a/chrome/browser/autofill/autofill_manager.cc
+++ b/chrome/browser/autofill/autofill_manager.cc
@@ -799,10 +799,22 @@ void AutoFillManager::FillCreditCardFormField(const CreditCard* credit_card,
DCHECK(type.group() == AutoFillType::CREDIT_CARD);
DCHECK(field);
- if (field->form_control_type() == ASCIIToUTF16("select-one"))
+ if (field->form_control_type() == ASCIIToUTF16("select-one")) {
autofill::FillSelectControl(credit_card, type, field);
- else
+ } else if (field->form_control_type() == ASCIIToUTF16("month")) {
+ // HTML5 input="month" consists of year-month.
+ string16 year = credit_card->GetFieldText(
+ AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR));
+ string16 month = credit_card->GetFieldText(
+ AutoFillType(CREDIT_CARD_EXP_MONTH));
+ if (!year.empty() && !month.empty()) {
+ // Fill the value only if |credit_card| includes both year and month
+ // information.
+ field->set_value(year + ASCIIToUTF16("-") + month);
+ }
+ } else {
field->set_value(credit_card->GetFieldText(type));
+ }
}
void AutoFillManager::FillFormField(const AutoFillProfile* profile,
diff --git a/chrome/browser/autofill/autofill_manager.h b/chrome/browser/autofill/autofill_manager.h
index 816cb67..569ffbc 100644
--- a/chrome/browser/autofill/autofill_manager.h
+++ b/chrome/browser/autofill/autofill_manager.h
@@ -224,6 +224,11 @@ class AutoFillManager : public TabContentsObserver,
friend class AutoFillManagerTest;
friend class FormStructureBrowserTest;
FRIEND_TEST_ALL_PREFIXES(AutoFillManagerTest, FillCreditCardForm);
+ FRIEND_TEST_ALL_PREFIXES(AutoFillManagerTest,
+ FillCreditCardFormNoYearNoMonth);
+ FRIEND_TEST_ALL_PREFIXES(AutoFillManagerTest, FillCreditCardFormYearNoMonth);
+ FRIEND_TEST_ALL_PREFIXES(AutoFillManagerTest, FillCreditCardFormNoYearMonth);
+ FRIEND_TEST_ALL_PREFIXES(AutoFillManagerTest, FillCreditCardFormYearMonth);
FRIEND_TEST_ALL_PREFIXES(AutoFillManagerTest, FillAddressForm);
FRIEND_TEST_ALL_PREFIXES(AutoFillManagerTest, FillAddressAndCreditCardForm);
FRIEND_TEST_ALL_PREFIXES(AutoFillManagerTest, FillAutoFilledForm);
diff --git a/chrome/browser/autofill/autofill_manager_unittest.cc b/chrome/browser/autofill/autofill_manager_unittest.cc
index 2f0f750..f58eaf8 100644
--- a/chrome/browser/autofill/autofill_manager_unittest.cc
+++ b/chrome/browser/autofill/autofill_manager_unittest.cc
@@ -90,6 +90,16 @@ class TestPersonalDataManager : public PersonalDataManager {
credit_cards_.reset();
}
+ void CreateTestCreditCardsYearAndMonth(const char* year, const char* month) {
+ ClearCreditCards();
+ CreditCard* credit_card = new CreditCard;
+ autofill_test::SetCreditCardInfo(credit_card, "Miku", "Miku Hatsune",
+ "4234567890654321", // Visa
+ month, year);
+ credit_card->set_guid("00000000-0000-0000-0000-000000000007");
+ credit_cards_->push_back(credit_card);
+ }
+
private:
void CreateTestAutoFillProfiles(ScopedVector<AutoFillProfile>* profiles) {
AutoFillProfile* profile = new AutoFillProfile;
@@ -184,12 +194,20 @@ void CreateTestAddressFormData(FormData* form) {
autofill_test::CreateTestFormField(
"Email", "email", "", "text", &field);
form->fields.push_back(field);
+ autofill_test::CreateTestFormField(
+ "Email", "email2", "", "email", &field);
+ form->fields.push_back(field);
+ autofill_test::CreateTestFormField(
+ "Phone Number", "phonenumber2", "", "tel", &field);
+ form->fields.push_back(field);
}
// Populates |form| with data corresponding to a simple credit card form.
// Note that this actually appends fields to the form data, which can be useful
// for building up more complex test forms.
-void CreateTestCreditCardFormData(FormData* form, bool is_https) {
+void CreateTestCreditCardFormData(FormData* form,
+ bool is_https,
+ bool use_month_type) {
form->name = ASCIIToUTF16("MyForm");
form->method = ASCIIToUTF16("POST");
if (is_https) {
@@ -208,12 +226,18 @@ void CreateTestCreditCardFormData(FormData* form, bool is_https) {
autofill_test::CreateTestFormField(
"Card Number", "cardnumber", "", "text", &field);
form->fields.push_back(field);
- autofill_test::CreateTestFormField(
- "Expiration Date", "ccmonth", "", "text", &field);
- form->fields.push_back(field);
- autofill_test::CreateTestFormField(
- "", "ccyear", "", "text", &field);
- form->fields.push_back(field);
+ if (use_month_type) {
+ autofill_test::CreateTestFormField(
+ "Expiration Date", "ccmonth", "", "month", &field);
+ form->fields.push_back(field);
+ } else {
+ autofill_test::CreateTestFormField(
+ "Expiration Date", "ccmonth", "", "text", &field);
+ form->fields.push_back(field);
+ autofill_test::CreateTestFormField(
+ "", "ccyear", "", "text", &field);
+ form->fields.push_back(field);
+ }
}
void ExpectSuggestions(int page_id,
@@ -244,7 +268,7 @@ void ExpectSuggestions(int page_id,
// Verifies that the |filled_form| has been filled with the given data.
// Verifies address fields if |has_address_fields| is true, and verifies
// credit card fields if |has_credit_card_fields| is true. Verifies both if both
-// are true.
+// are true. |use_month_type| is used for credit card input month type.
void ExpectFilledForm(int page_id,
const FormData& filled_form,
int expected_page_id,
@@ -265,10 +289,11 @@ void ExpectFilledForm(int page_id,
const char* expiration_month,
const char* expiration_year,
bool has_address_fields,
- bool has_credit_card_fields) {
+ bool has_credit_card_fields,
+ bool use_month_type) {
// The number of fields in the address and credit card forms created above.
- const size_t kAddressFormSize = 12;
- const size_t kCreditCardFormSize = 4;
+ const size_t kAddressFormSize = 14;
+ const size_t kCreditCardFormSize = use_month_type ? 3 : 4;
EXPECT_EQ(expected_page_id, page_id);
EXPECT_EQ(ASCIIToUTF16("MyForm"), filled_form.name);
@@ -327,6 +352,12 @@ void ExpectFilledForm(int page_id,
autofill_test::CreateTestFormField(
"Email", "email", email, "text", &field);
EXPECT_TRUE(field.StrictlyEqualsHack(filled_form.fields[11]));
+ autofill_test::CreateTestFormField(
+ "Email", "email2", email, "email", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(filled_form.fields[12]));
+ autofill_test::CreateTestFormField(
+ "Phone Number", "phonenumber2", phone, "tel", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(filled_form.fields[13]));
}
if (has_credit_card_fields) {
@@ -337,12 +368,23 @@ void ExpectFilledForm(int page_id,
autofill_test::CreateTestFormField(
"Card Number", "cardnumber", card_number, "text", &field);
EXPECT_TRUE(field.StrictlyEqualsHack(filled_form.fields[offset + 1]));
- autofill_test::CreateTestFormField(
- "Expiration Date", "ccmonth", expiration_month, "text", &field);
- EXPECT_TRUE(field.StrictlyEqualsHack(filled_form.fields[offset + 2]));
- autofill_test::CreateTestFormField(
- "", "ccyear", expiration_year, "text", &field);
- EXPECT_TRUE(field.StrictlyEqualsHack(filled_form.fields[offset + 3]));
+ if (use_month_type) {
+ std::string exp_year = expiration_year;
+ std::string exp_month = expiration_month;
+ std::string date;
+ if (!exp_year.empty() && !exp_month.empty())
+ date = exp_year + "-" + exp_month;
+ autofill_test::CreateTestFormField(
+ "Expiration Date", "ccmonth", date.c_str(), "month", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(filled_form.fields[offset + 2]));
+ } else {
+ autofill_test::CreateTestFormField(
+ "Expiration Date", "ccmonth", expiration_month, "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(filled_form.fields[offset + 2]));
+ autofill_test::CreateTestFormField(
+ "", "ccyear", expiration_year, "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(filled_form.fields[offset + 3]));
+ }
}
}
@@ -354,7 +396,7 @@ void ExpectFilledAddressFormElvis(int page_id,
"Presley", "3734 Elvis Presley Blvd.", "Apt. 10", "Memphis",
"Tennessee", "38116", "USA", "12345678901", "",
"theking@gmail.com", "", "", "", "", true,
- has_credit_card_fields);
+ has_credit_card_fields, false);
}
void ExpectFilledCreditCardFormElvis(int page_id,
@@ -364,7 +406,19 @@ void ExpectFilledCreditCardFormElvis(int page_id,
ExpectFilledForm(page_id, filled_form, expected_page_id,
"", "", "", "", "", "", "", "", "", "", "", "",
"Elvis Presley", "4234567890123456", "04", "2012",
- has_address_fields, true);
+ has_address_fields, true, false);
+}
+
+void ExpectFilledCreditCardYearMonthWithYearMonth(int page_id,
+ const FormData& filled_form,
+ int expected_page_id,
+ bool has_address_fields,
+ const char* year,
+ const char* month) {
+ ExpectFilledForm(page_id, filled_form, expected_page_id,
+ "", "", "", "", "", "", "", "", "", "", "", "",
+ "Miku Hatsune", "4234567890654321", month, year,
+ has_address_fields, true, true);
}
class TestAutoFillManager : public AutoFillManager {
@@ -768,7 +822,7 @@ TEST_F(AutoFillManagerTest, GetProfileSuggestionsMethodGet) {
TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsEmptyValue) {
// Set up our form data.
FormData form;
- CreateTestCreditCardFormData(&form, true);
+ CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
@@ -811,7 +865,7 @@ TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsEmptyValue) {
TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsMatchCharacter) {
// Set up our form data.
FormData form;
- CreateTestCreditCardFormData(&form, true);
+ CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
@@ -847,7 +901,7 @@ TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsMatchCharacter) {
TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsNonCCNumber) {
// Set up our form data.
FormData form;
- CreateTestCreditCardFormData(&form, true);
+ CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
@@ -890,7 +944,7 @@ TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsNonCCNumber) {
TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsNonHTTPS) {
// Set up our form data.
FormData form;
- CreateTestCreditCardFormData(&form, false);
+ CreateTestCreditCardFormData(&form, false, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
@@ -955,7 +1009,7 @@ TEST_F(AutoFillManagerTest, GetAddressAndCreditCardSuggestions) {
// Set up our form data.
FormData form;
CreateTestAddressFormData(&form);
- CreateTestCreditCardFormData(&form, true);
+ CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
@@ -1029,7 +1083,7 @@ TEST_F(AutoFillManagerTest, GetAddressAndCreditCardSuggestionsNonHttps) {
// Set up our form data.
FormData form;
CreateTestAddressFormData(&form);
- CreateTestCreditCardFormData(&form, false);
+ CreateTestCreditCardFormData(&form, false, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
@@ -1289,7 +1343,7 @@ TEST_F(AutoFillManagerTest, FillAddressForm) {
TEST_F(AutoFillManagerTest, FillCreditCardForm) {
// Set up our form data.
FormData form;
- CreateTestCreditCardFormData(&form, true);
+ CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
@@ -1304,12 +1358,110 @@ TEST_F(AutoFillManagerTest, FillCreditCardForm) {
ExpectFilledCreditCardFormElvis(page_id, results, kDefaultPageID, false);
}
+// Test that we correctly fill a credit card form with month input type.
+// 1. year empty, month empty
+TEST_F(AutoFillManagerTest, FillCreditCardFormNoYearNoMonth) {
+ // Same as the SetUp(), but generate 4 credit cards with year month
+ // combination.
+ test_personal_data_->CreateTestCreditCardsYearAndMonth("", "");
+ // Set up our form data.
+ FormData form;
+ CreateTestCreditCardFormData(&form, true, true);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ std::string guid = autofill_manager_->GetLabeledCreditCard("Miku")->guid();
+ FillAutoFillFormData(
+ kDefaultPageID, form, *form.fields.begin(),
+ autofill_manager_->PackGUIDs(guid, std::string()));
+
+ int page_id = 0;
+ FormData results;
+ EXPECT_TRUE(GetAutoFillFormDataFilledMessage(&page_id, &results));
+ ExpectFilledCreditCardYearMonthWithYearMonth(page_id, results,
+ kDefaultPageID, false, "", "");
+}
+
+
+// Test that we correctly fill a credit card form with month input type.
+// 2. year empty, month non-empty
+TEST_F(AutoFillManagerTest, FillCreditCardFormNoYearMonth) {
+ // Same as the SetUp(), but generate 4 credit cards with year month
+ // combination.
+ test_personal_data_->CreateTestCreditCardsYearAndMonth("", "04");
+ // Set up our form data.
+ FormData form;
+ CreateTestCreditCardFormData(&form, true, true);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ std::string guid = autofill_manager_->GetLabeledCreditCard("Miku")->guid();
+ FillAutoFillFormData(
+ kDefaultPageID, form, *form.fields.begin(),
+ autofill_manager_->PackGUIDs(guid, std::string()));
+
+ int page_id = 0;
+ FormData results;
+ EXPECT_TRUE(GetAutoFillFormDataFilledMessage(&page_id, &results));
+ ExpectFilledCreditCardYearMonthWithYearMonth(page_id, results,
+ kDefaultPageID, false, "", "04");
+}
+
+// Test that we correctly fill a credit card form with month input type.
+// 3. year non-empty, month empty
+TEST_F(AutoFillManagerTest, FillCreditCardFormYearNoMonth) {
+ // Same as the SetUp(), but generate 4 credit cards with year month
+ // combination.
+ test_personal_data_->CreateTestCreditCardsYearAndMonth("2012", "");
+ // Set up our form data.
+ FormData form;
+ CreateTestCreditCardFormData(&form, true, true);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ std::string guid = autofill_manager_->GetLabeledCreditCard("Miku")->guid();
+ FillAutoFillFormData(
+ kDefaultPageID, form, *form.fields.begin(),
+ autofill_manager_->PackGUIDs(guid, std::string()));
+
+ int page_id = 0;
+ FormData results;
+ EXPECT_TRUE(GetAutoFillFormDataFilledMessage(&page_id, &results));
+ ExpectFilledCreditCardYearMonthWithYearMonth(page_id, results,
+ kDefaultPageID, false, "2012", "");
+}
+
+// Test that we correctly fill a credit card form with month input type.
+// 4. year non-empty, month empty
+TEST_F(AutoFillManagerTest, FillCreditCardFormYearMonth) {
+ // Same as the SetUp(), but generate 4 credit cards with year month
+ // combination.
+ test_personal_data_->ClearCreditCards();
+ test_personal_data_->CreateTestCreditCardsYearAndMonth("2012", "04");
+ // Set up our form data.
+ FormData form;
+ CreateTestCreditCardFormData(&form, true, true);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ std::string guid = autofill_manager_->GetLabeledCreditCard("Miku")->guid();
+ FillAutoFillFormData(
+ kDefaultPageID, form, *form.fields.begin(),
+ autofill_manager_->PackGUIDs(guid, std::string()));
+
+ int page_id = 0;
+ FormData results;
+ EXPECT_TRUE(GetAutoFillFormDataFilledMessage(&page_id, &results));
+ ExpectFilledCreditCardYearMonthWithYearMonth(page_id, results,
+ kDefaultPageID, false, "2012", "04");
+}
+
// Test that we correctly fill a combined address and credit card form.
TEST_F(AutoFillManagerTest, FillAddressAndCreditCardForm) {
// Set up our form data.
FormData form;
CreateTestAddressFormData(&form);
- CreateTestCreditCardFormData(&form, true);
+ CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
@@ -1349,7 +1501,7 @@ TEST_F(AutoFillManagerTest, FillAutoFilledForm) {
CreateTestAddressFormData(&form);
// Mark one of the address fields as autofilled.
form.fields[4].set_autofilled(true);
- CreateTestCreditCardFormData(&form, true);
+ CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
@@ -1366,7 +1518,7 @@ TEST_F(AutoFillManagerTest, FillAutoFilledForm) {
SCOPED_TRACE("Address");
ExpectFilledForm(page_id, results, kDefaultPageID,
"Elvis", "", "", "", "", "", "", "", "", "", "", "",
- "", "", "", "", true, true);
+ "", "", "", "", true, true, false);
}
// Now fill the credit card data.
@@ -1402,7 +1554,7 @@ TEST_F(AutoFillManagerTest, FillAutoFilledForm) {
SCOPED_TRACE("Credit card 2");
ExpectFilledForm(page_id, results, kPageID3,
"", "", "", "", "", "", "", "", "", "", "", "",
- "", "", "", "2012", true, true);
+ "", "", "", "2012", true, true, false);
}
}
diff --git a/chrome/browser/autofill/credit_card.cc b/chrome/browser/autofill/credit_card.cc
index 6296eba..20fca4e 100644
--- a/chrome/browser/autofill/credit_card.cc
+++ b/chrome/browser/autofill/credit_card.cc
@@ -7,6 +7,7 @@
#include <string>
#include "base/basictypes.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/string_number_conversions.h"
#include "base/string16.h"
@@ -15,6 +16,8 @@
#include "chrome/browser/autofill/field_types.h"
#include "chrome/common/guid.h"
#include "grit/generated_resources.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebRegularExpression.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
#include "ui/base/l10n/l10n_util.h"
namespace {
@@ -329,6 +332,26 @@ const string16 CreditCard::Label() const {
return label_;
}
+void CreditCard::SetInfoForMonthInputType(const string16& value) {
+ // Check if |text| is "yyyy-mm" format first, and check normal month format.
+ WebKit::WebRegularExpression re(WebKit::WebString("^[0-9]{4}\\-[0-9]{1,2}$"),
+ WebKit::WebTextCaseInsensitive);
+ bool match = re.match(WebKit::WebString(StringToLowerASCII(value))) != -1;
+ if (match) {
+ std::vector<string16> year_month;
+ base::SplitString(value, L'-', &year_month);
+ DCHECK_EQ((int)year_month.size(), 2);
+ int num = 0;
+ bool converted = false;
+ converted = base::StringToInt(year_month[0], &num);
+ DCHECK(converted);
+ set_expiration_year(num);
+ converted = base::StringToInt(year_month[1], &num);
+ DCHECK(converted);
+ set_expiration_month(num);
+ }
+}
+
string16 CreditCard::ObfuscatedNumber() const {
if (number().empty())
return string16(); // No CC number, means empty preview.
diff --git a/chrome/browser/autofill/credit_card.h b/chrome/browser/autofill/credit_card.h
index 2b2d089..951b605 100644
--- a/chrome/browser/autofill/credit_card.h
+++ b/chrome/browser/autofill/credit_card.h
@@ -34,6 +34,9 @@ class CreditCard : public FormGroup {
virtual void SetInfo(const AutoFillType& type, const string16& value);
virtual const string16 Label() const;
+ // Special method to set value for HTML5 month input type.
+ void SetInfoForMonthInputType(const string16& value);
+
// The number altered for display, for example: ******1234
string16 ObfuscatedNumber() const;
// Credit card preview summary, for example: ******1234, Exp: 01/2020
diff --git a/chrome/browser/autofill/credit_card_field.cc b/chrome/browser/autofill/credit_card_field.cc
index 7837463..746bdf9 100644
--- a/chrome/browser/autofill/credit_card_field.cc
+++ b/chrome/browser/autofill/credit_card_field.cc
@@ -118,35 +118,40 @@ CreditCardField* CreditCardField::Parse(
&credit_card_field->number_))
continue;
- // "Expiration date" is the most common label here, but some pages have
- // "Expires", "exp. date" or "exp. month" and "exp. year". We also look for
- // the field names ccmonth and ccyear, which appear on at least 4 of our
- // test pages.
- //
- // -> On at least one page (The China Shop2.html) we find only the labels
- // "month" and "year". So for now we match these words directly; we'll
- // see if this turns out to be too general.
- //
- // Toolbar Bug 51451: indeed, simply matching "month" is too general for
- // https://rps.fidelity.com/ftgw/rps/RtlCust/CreatePIN/Init.
- // Instead, we match only words beginning with "month".
- if (is_ecml)
- pattern = GetEcmlPattern(kEcmlCardExpireMonth);
- else
- pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EXPIRATION_MONTH_RE);
-
- if ((!credit_card_field->expiration_month_ ||
- credit_card_field->expiration_month_->IsEmpty()) &&
- ParseText(&q, pattern, &credit_card_field->expiration_month_)) {
+ if ((*q) && LowerCaseEqualsASCII((*q)->form_control_type(), "month")) {
+ credit_card_field->expiration_month_ = *q++;
+ } else {
+ // "Expiration date" is the most common label here, but some pages have
+ // "Expires", "exp. date" or "exp. month" and "exp. year". We also look
+ // for the field names ccmonth and ccyear, which appear on at least 4 of
+ // our test pages.
+ //
+ // -> On at least one page (The China Shop2.html) we find only the labels
+ // "month" and "year". So for now we match these words directly; we'll
+ // see if this turns out to be too general.
+ //
+ // Toolbar Bug 51451: indeed, simply matching "month" is too general for
+ // https://rps.fidelity.com/ftgw/rps/RtlCust/CreatePIN/Init.
+ // Instead, we match only words beginning with "month".
if (is_ecml)
- pattern = GetEcmlPattern(kEcmlCardExpireYear);
+ pattern = GetEcmlPattern(kEcmlCardExpireMonth);
else
- pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EXPIRATION_DATE_RE);
+ pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EXPIRATION_MONTH_RE);
- if (!ParseText(&q, pattern, &credit_card_field->expiration_year_))
- return NULL;
+ if ((!credit_card_field->expiration_month_ ||
+ credit_card_field->expiration_month_->IsEmpty()) &&
+ ParseText(&q, pattern, &credit_card_field->expiration_month_)) {
- continue;
+ if (is_ecml)
+ pattern = GetEcmlPattern(kEcmlCardExpireYear);
+ else
+ pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EXPIRATION_DATE_RE);
+
+ if (!ParseText(&q, pattern, &credit_card_field->expiration_year_)) {
+ return NULL;
+ }
+ continue;
+ }
}
if (ParseText(&q, GetEcmlPattern(kEcmlCardExpireDay)))
@@ -180,7 +185,10 @@ CreditCardField* CreditCardField::Parse(
// the cvc and date were found independently they are returned.
if ((credit_card_field->number_ || credit_card_field->verification_) &&
credit_card_field->expiration_month_ &&
- credit_card_field->expiration_year_) {
+ (credit_card_field->expiration_year_ ||
+ (LowerCaseEqualsASCII(
+ credit_card_field->expiration_month_->form_control_type(),
+ "month")))) {
*iter = q;
return credit_card_field.release();
}
diff --git a/chrome/browser/autofill/personal_data_manager.cc b/chrome/browser/autofill/personal_data_manager.cc
index 8430b15..8dfa553 100644
--- a/chrome/browser/autofill/personal_data_manager.cc
+++ b/chrome/browser/autofill/personal_data_manager.cc
@@ -191,8 +191,13 @@ bool PersonalDataManager::ImportFormData(
// If the user has a password set, we have no way of setting credit
// card numbers.
if (!HasPassword()) {
- imported_credit_card_->SetInfo(AutoFillType(field_type.field_type()),
- value);
+ if (LowerCaseEqualsASCII(field->form_control_type(), "month")) {
+ DCHECK_EQ(CREDIT_CARD_EXP_MONTH, field_type.field_type());
+ imported_credit_card_->SetInfoForMonthInputType(value);
+ } else {
+ imported_credit_card_->SetInfo(
+ AutoFillType(field_type.field_type()), value);
+ }
++importable_credit_card_fields;
}
} else {
diff --git a/chrome/renderer/autofill/form_manager.cc b/chrome/renderer/autofill/form_manager.cc
index cd24300..3e2b482 100644
--- a/chrome/renderer/autofill/form_manager.cc
+++ b/chrome/renderer/autofill/form_manager.cc
@@ -52,10 +52,13 @@ const size_t kRequiredAutoFillFields = 3;
// The maximum length allowed for form data.
const size_t kMaxDataLength = 1024;
-// TODO(isherman): Replace calls to this with IsTextInput() once
-// http://codereview.chromium.org/6033010/ lands.
-bool IsTextElement(const WebFormControlElement& element) {
- return element.formControlType() == WebString::fromUTF8("text");
+// In HTML5, all text fields except password are text input fields to
+// autocomplete.
+bool IsTextInput(const WebInputElement* element) {
+ if (!element)
+ return false;
+
+ return element->isTextField() && !element->isPasswordField();
}
bool IsSelectElement(const WebFormControlElement& element) {
@@ -335,7 +338,8 @@ void FormManager::WebFormControlElementToFormField(
field->set_name(element.nameForAutofill());
field->set_form_control_type(element.formControlType());
- if (IsTextElement(element)) {
+ const WebInputElement* input_element = toWebInputElement(&element);
+ if (IsTextInput(input_element)) {
const WebInputElement& input_element = element.toConst<WebInputElement>();
field->set_max_length(input_element.maxLength());
field->set_autofilled(input_element.isAutofilled());
@@ -350,10 +354,9 @@ void FormManager::WebFormControlElementToFormField(
return;
string16 value;
- if (IsTextElement(element) ||
+ if (IsTextInput(input_element) ||
element.formControlType() == WebString::fromUTF8("hidden")) {
- const WebInputElement& input_element = element.toConst<WebInputElement>();
- value = input_element.value();
+ value = input_element->value();
} else if (IsSelectElement(element)) {
const WebSelectElement select_element = element.toConst<WebSelectElement>();
value = select_element.value();
@@ -444,12 +447,10 @@ bool FormManager::WebFormElementToFormData(const WebFormElement& element,
for (size_t i = 0; i < control_elements.size(); ++i) {
const WebFormControlElement& control_element = control_elements[i];
- if (requirements & REQUIRE_AUTOCOMPLETE && IsTextElement(control_element)) {
- const WebInputElement& input_element =
- control_element.toConst<WebInputElement>();
- if (!input_element.autoComplete())
- continue;
- }
+ const WebInputElement* input_element = toWebInputElement(&control_element);
+ if (requirements & REQUIRE_AUTOCOMPLETE && IsTextInput(input_element) &&
+ !input_element->autoComplete())
+ continue;
if (requirements & REQUIRE_ENABLED && !control_element.isEnabled())
continue;
@@ -654,21 +655,21 @@ bool FormManager::ClearFormWithNode(const WebNode& node) {
for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
WebFormControlElement element = form_element->control_elements[i];
- if (IsTextElement(element)) {
- WebInputElement input_element = element.to<WebInputElement>();
+ WebInputElement* input_element = toWebInputElement(&element);
+ if (IsTextInput(input_element)) {
// We don't modify the value of disabled fields.
- if (!input_element.isEnabled())
+ if (!input_element->isEnabled())
continue;
- input_element.setValue(string16());
- input_element.setAutofilled(false);
+ input_element->setValue(string16());
+ input_element->setAutofilled(false);
// Clearing the value in the focused node (above) can cause selection
// to be lost. We force selection range to restore the text cursor.
- if (node == input_element) {
- int length = input_element.value().length();
- input_element.setSelectionRange(length, length);
+ if (node == *input_element) {
+ int length = input_element->value().length();
+ input_element->setSelectionRange(length, length);
}
} else if (IsSelectElement(element)) {
WebSelectElement select_element = element.to<WebSelectElement>();
@@ -686,44 +687,43 @@ bool FormManager::ClearPreviewedFormWithNode(const WebNode& node,
return false;
for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
- WebFormControlElement* element = &form_element->control_elements[i];
-
+ WebInputElement* input_element =
+ toWebInputElement(&form_element->control_elements[i]);
// Only text input elements can be previewed.
- if (!IsTextElement(*element))
+ if (!IsTextInput(input_element))
continue;
// If the input element has not been auto-filled, FormManager has not
// previewed this field, so we have nothing to reset.
- WebInputElement input_element = element->to<WebInputElement>();
- if (!input_element.isAutofilled())
+ if (!input_element->isAutofilled())
continue;
// There might be unrelated elements in this form which have already been
// auto-filled. For example, the user might have already filled the address
// part of a form and now be dealing with the credit card section. We only
// want to reset the auto-filled status for fields that were previewed.
- if (input_element.suggestedValue().isEmpty())
+ if (input_element->suggestedValue().isEmpty())
continue;
// Clear the suggested value. For the initiating node, also restore the
// original value.
- input_element.setSuggestedValue(WebString());
- bool is_initiating_node = (node == input_element);
+ input_element->setSuggestedValue(WebString());
+ bool is_initiating_node = (node == *input_element);
if (is_initiating_node) {
// Call |setValue()| to force the renderer to update the field's displayed
// value.
- input_element.setValue(input_element.value());
- input_element.setAutofilled(was_autofilled);
+ input_element->setValue(input_element->value());
+ input_element->setAutofilled(was_autofilled);
} else {
- input_element.setAutofilled(false);
+ input_element->setAutofilled(false);
}
// Clearing the suggested value in the focused node (above) can cause
// selection to be lost. We force selection range to restore the text
// cursor.
if (is_initiating_node) {
- int length = input_element.value().length();
- input_element.setSelectionRange(length, length);
+ int length = input_element->value().length();
+ input_element->setSelectionRange(length, length);
}
}
@@ -750,12 +750,12 @@ bool FormManager::FormWithNodeIsAutoFilled(const WebNode& node) {
return false;
for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
- WebFormControlElement element = form_element->control_elements[i];
- if (!IsTextElement(element))
+ WebInputElement* input_element =
+ toWebInputElement(&form_element->control_elements[i]);
+ if (!IsTextInput(input_element))
continue;
- const WebInputElement& input_element = element.to<WebInputElement>();
- if (input_element.isAutofilled())
+ if (input_element->isAutofilled())
return true;
}
@@ -836,22 +836,21 @@ void FormManager::ForEachMatchingFormField(FormElement* form,
// More than likely |requirements| will contain REQUIRE_AUTOCOMPLETE and/or
// REQUIRE_EMPTY, which both require text form control elements, so special-
// case this type of element.
- if (IsTextElement(*element)) {
- const WebInputElement& input_element =
- element->toConst<WebInputElement>();
+ const WebInputElement* input_element = toWebInputElement(element);
+ if (IsTextInput(input_element)) {
// TODO(jhawkins): WebKit currently doesn't handle the autocomplete
// attribute for select control elements, but it probably should.
- if (requirements & REQUIRE_AUTOCOMPLETE && !input_element.autoComplete())
+ if (requirements & REQUIRE_AUTOCOMPLETE && !input_element->autoComplete())
continue;
- is_initiating_node = (input_element == node);
+ is_initiating_node = (*input_element == node);
// Don't require the node that initiated the auto-fill process to be
// empty. The user is typing in this field and we should complete the
// value when the user selects a value to fill out.
if (requirements & REQUIRE_EMPTY &&
!is_initiating_node &&
- !input_element.value().isEmpty())
+ !input_element->value().isEmpty())
continue;
}
@@ -874,16 +873,17 @@ void FormManager::FillFormField(WebFormControlElement* field,
if (data->value().empty())
return;
- if (IsTextElement(*field)) {
- WebInputElement input_element = field->to<WebInputElement>();
+ WebInputElement* input_element = toWebInputElement(field);
+ if (IsTextInput(input_element)) {
// If the maxlength attribute contains a negative value, maxLength()
// returns the default maxlength value.
- input_element.setValue(data->value().substr(0, input_element.maxLength()));
- input_element.setAutofilled(true);
+ input_element->setValue(
+ data->value().substr(0, input_element->maxLength()));
+ input_element->setAutofilled(true);
if (is_initiating_node) {
- int length = input_element.value().length();
- input_element.setSelectionRange(length, length);
+ int length = input_element->value().length();
+ input_element->setSelectionRange(length, length);
}
} else if (IsSelectElement(*field)) {
WebSelectElement select_element = field->to<WebSelectElement>();
@@ -899,18 +899,18 @@ void FormManager::PreviewFormField(WebFormControlElement* field,
return;
// Only preview input fields.
- if (!IsTextElement(*field))
+ WebInputElement* input_element = toWebInputElement(field);
+ if (!IsTextInput(input_element))
return;
- WebInputElement input_element = field->to<WebInputElement>();
-
// If the maxlength attribute contains a negative value, maxLength()
// returns the default maxlength value.
- input_element.setSuggestedValue(
- data->value().substr(0, input_element.maxLength()));
- input_element.setAutofilled(true);
+ input_element->setSuggestedValue(
+ data->value().substr(0, input_element->maxLength()));
+ input_element->setAutofilled(true);
if (is_initiating_node)
- input_element.setSelectionRange(0, input_element.suggestedValue().length());
+ input_element->setSelectionRange(0,
+ input_element->suggestedValue().length());
}
} // namespace autofill
diff --git a/chrome/renderer/autofill/form_manager_browsertest.cc b/chrome/renderer/autofill/form_manager_browsertest.cc
index ca71894..d6243fa 100644
--- a/chrome/renderer/autofill/form_manager_browsertest.cc
+++ b/chrome/renderer/autofill/form_manager_browsertest.cc
@@ -2846,6 +2846,8 @@ TEST_F(FormManagerTest, ClearPreviewedFormWithNode) {
" <INPUT type=\"text\" id=\"firstname\" value=\"Wyatt\"/>"
" <INPUT type=\"text\" id=\"lastname\"/>"
" <INPUT type=\"text\" id=\"email\"/>"
+ " <INPUT type=\"email\" id=\"email2\"/>"
+ " <INPUT type=\"tel\" id=\"phone\"/>"
" <INPUT type=\"submit\" value=\"Send\"/>"
"</FORM>");
@@ -2870,10 +2872,18 @@ TEST_F(FormManagerTest, ClearPreviewedFormWithNode) {
WebInputElement email =
web_frame->document().getElementById("email").to<WebInputElement>();
email.setAutofilled(true);
+ WebInputElement email2 =
+ web_frame->document().getElementById("email2").to<WebInputElement>();
+ email2.setAutofilled(true);
+ WebInputElement phone =
+ web_frame->document().getElementById("phone").to<WebInputElement>();
+ phone.setAutofilled(true);
// Set the suggested values on two of the elements.
lastname.setSuggestedValue(ASCIIToUTF16("Earp"));
email.setSuggestedValue(ASCIIToUTF16("wyatt@earp.com"));
+ email2.setSuggestedValue(ASCIIToUTF16("wyatt@earp.com"));
+ phone.setSuggestedValue(ASCIIToUTF16("650-777-9999"));
// Clear the previewed fields.
EXPECT_TRUE(form_manager.ClearPreviewedFormWithNode(lastname, false));
@@ -2890,6 +2900,12 @@ TEST_F(FormManagerTest, ClearPreviewedFormWithNode) {
EXPECT_TRUE(email.value().isEmpty());
EXPECT_TRUE(email.suggestedValue().isEmpty());
EXPECT_FALSE(email.isAutofilled());
+ EXPECT_TRUE(email2.value().isEmpty());
+ EXPECT_TRUE(email2.suggestedValue().isEmpty());
+ EXPECT_FALSE(email2.isAutofilled());
+ EXPECT_TRUE(phone.value().isEmpty());
+ EXPECT_TRUE(phone.suggestedValue().isEmpty());
+ EXPECT_FALSE(phone.isAutofilled());
// Verify that the cursor position has been updated.
EXPECT_EQ(0, lastname.selectionStart());
@@ -2901,6 +2917,8 @@ TEST_F(FormManagerTest, ClearPreviewedFormWithNonEmptyInitiatingNode) {
" <INPUT type=\"text\" id=\"firstname\" value=\"W\"/>"
" <INPUT type=\"text\" id=\"lastname\"/>"
" <INPUT type=\"text\" id=\"email\"/>"
+ " <INPUT type=\"email\" id=\"email2\"/>"
+ " <INPUT type=\"tel\" id=\"phone\"/>"
" <INPUT type=\"submit\" value=\"Send\"/>"
"</FORM>");
@@ -2925,11 +2943,20 @@ TEST_F(FormManagerTest, ClearPreviewedFormWithNonEmptyInitiatingNode) {
WebInputElement email =
web_frame->document().getElementById("email").to<WebInputElement>();
email.setAutofilled(true);
+ WebInputElement email2 =
+ web_frame->document().getElementById("email2").to<WebInputElement>();
+ email2.setAutofilled(true);
+ WebInputElement phone =
+ web_frame->document().getElementById("phone").to<WebInputElement>();
+ phone.setAutofilled(true);
+
// Set the suggested values on all of the elements.
firstname.setSuggestedValue(ASCIIToUTF16("Wyatt"));
lastname.setSuggestedValue(ASCIIToUTF16("Earp"));
email.setSuggestedValue(ASCIIToUTF16("wyatt@earp.com"));
+ email2.setSuggestedValue(ASCIIToUTF16("wyatt@earp.com"));
+ phone.setSuggestedValue(ASCIIToUTF16("650-777-9999"));
// Clear the previewed fields.
EXPECT_TRUE(form_manager.ClearPreviewedFormWithNode(firstname, false));
@@ -2948,6 +2975,12 @@ TEST_F(FormManagerTest, ClearPreviewedFormWithNonEmptyInitiatingNode) {
EXPECT_TRUE(email.value().isEmpty());
EXPECT_TRUE(email.suggestedValue().isEmpty());
EXPECT_FALSE(email.isAutofilled());
+ EXPECT_TRUE(email2.value().isEmpty());
+ EXPECT_TRUE(email2.suggestedValue().isEmpty());
+ EXPECT_FALSE(email2.isAutofilled());
+ EXPECT_TRUE(phone.value().isEmpty());
+ EXPECT_TRUE(phone.suggestedValue().isEmpty());
+ EXPECT_FALSE(phone.isAutofilled());
}
TEST_F(FormManagerTest, ClearPreviewedFormWithAutofilledInitiatingNode) {
@@ -2955,6 +2988,8 @@ TEST_F(FormManagerTest, ClearPreviewedFormWithAutofilledInitiatingNode) {
" <INPUT type=\"text\" id=\"firstname\" value=\"W\"/>"
" <INPUT type=\"text\" id=\"lastname\"/>"
" <INPUT type=\"text\" id=\"email\"/>"
+ " <INPUT type=\"email\" id=\"email2\"/>"
+ " <INPUT type=\"tel\" id=\"phone\"/>"
" <INPUT type=\"submit\" value=\"Send\"/>"
"</FORM>");
@@ -2979,11 +3014,19 @@ TEST_F(FormManagerTest, ClearPreviewedFormWithAutofilledInitiatingNode) {
WebInputElement email =
web_frame->document().getElementById("email").to<WebInputElement>();
email.setAutofilled(true);
+ WebInputElement email2 =
+ web_frame->document().getElementById("email2").to<WebInputElement>();
+ email2.setAutofilled(true);
+ WebInputElement phone =
+ web_frame->document().getElementById("phone").to<WebInputElement>();
+ phone.setAutofilled(true);
// Set the suggested values on all of the elements.
firstname.setSuggestedValue(ASCIIToUTF16("Wyatt"));
lastname.setSuggestedValue(ASCIIToUTF16("Earp"));
email.setSuggestedValue(ASCIIToUTF16("wyatt@earp.com"));
+ email2.setSuggestedValue(ASCIIToUTF16("wyatt@earp.com"));
+ phone.setSuggestedValue(ASCIIToUTF16("650-777-9999"));
// Clear the previewed fields.
EXPECT_TRUE(form_manager.ClearPreviewedFormWithNode(firstname, true));
@@ -3002,6 +3045,12 @@ TEST_F(FormManagerTest, ClearPreviewedFormWithAutofilledInitiatingNode) {
EXPECT_TRUE(email.value().isEmpty());
EXPECT_TRUE(email.suggestedValue().isEmpty());
EXPECT_FALSE(email.isAutofilled());
+ EXPECT_TRUE(email2.value().isEmpty());
+ EXPECT_TRUE(email2.suggestedValue().isEmpty());
+ EXPECT_FALSE(email2.isAutofilled());
+ EXPECT_TRUE(phone.value().isEmpty());
+ EXPECT_TRUE(phone.suggestedValue().isEmpty());
+ EXPECT_FALSE(phone.isAutofilled());
}
TEST_F(FormManagerTest, FormWithNodeIsAutoFilled) {
@@ -3009,6 +3058,8 @@ TEST_F(FormManagerTest, FormWithNodeIsAutoFilled) {
" <INPUT type=\"text\" id=\"firstname\" value=\"Wyatt\"/>"
" <INPUT type=\"text\" id=\"lastname\"/>"
" <INPUT type=\"text\" id=\"email\"/>"
+ " <INPUT type=\"email\" id=\"email2\"/>"
+ " <INPUT type=\"tel\" id=\"phone\"/>"
" <INPUT type=\"submit\" value=\"Send\"/>"
"</FORM>");