Commit 92e7407c authored by Rouslan Solomakhin's avatar Rouslan Solomakhin Committed by Commit Bot

Format-as-you-type for the phone number in web payments UI on desktop.

Before this patch, typing "3103106000" into a phone number field in web
payments UI on desktop would leave the field as-is, which is difficult
to read.

This patch extends ValidationDelegate to also handle text field
formatting. Formatting happens only when the user is typing at the end
of the field or when user has left the field (blur). Typing in the
middle of the field does not cause reformat because Views does not have
functionality to position the cursor, which is required to make
auto-formatting feel natural.

After this patch, typing "3103106000" into a phone number field in web
payments UI on desktop will format-as-you-type this number into "+1
310-310-6000".

Bug: 725161
Change-Id: Id39de49e2a79a681ff2615541489be057b37d2de
Reviewed-on: https://chromium-review.googlesource.com/511422Reviewed-by: default avatarAnthony Vallee-Dubois <anthonyvd@chromium.org>
Commit-Queue: Rouslan Solomakhin <rouslan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#473945}
parent ad392f2d
......@@ -1588,6 +1588,7 @@ split_static_library("ui") {
"views/payments/validating_combobox.h",
"views/payments/validating_textfield.cc",
"views/payments/validating_textfield.h",
"views/payments/validation_delegate.cc",
"views/payments/validation_delegate.h",
"views/payments/view_stack.cc",
"views/payments/view_stack.h",
......
......@@ -158,6 +158,19 @@ ContactInfoEditorViewController::ContactInfoValidationDelegate::
ContactInfoEditorViewController::ContactInfoValidationDelegate::
~ContactInfoValidationDelegate() {}
bool ContactInfoEditorViewController::ContactInfoValidationDelegate::
ShouldFormat() {
return field_.type == autofill::PHONE_HOME_WHOLE_NUMBER;
}
base::string16
ContactInfoEditorViewController::ContactInfoValidationDelegate::Format(
const base::string16& text) {
return base::UTF8ToUTF16(data_util::FormatPhoneForDisplay(
base::UTF16ToUTF8(text),
autofill::AutofillCountry::CountryCodeForLocale(locale_)));
}
bool ContactInfoEditorViewController::ContactInfoValidationDelegate::
IsValidTextfield(views::Textfield* textfield) {
return ValidateTextfield(textfield, nullptr);
......
......@@ -72,6 +72,8 @@ class ContactInfoEditorViewController : public EditorViewController {
~ContactInfoValidationDelegate() override;
// ValidationDelegate:
bool ShouldFormat() override;
base::string16 Format(const base::string16& text) override;
bool IsValidTextfield(views::Textfield* textfield) override;
bool IsValidCombobox(views::Combobox* combobox) override;
bool TextfieldValueChanged(views::Textfield* textfield) override;
......
......@@ -63,7 +63,7 @@ IN_PROC_BROWSER_TEST_F(PaymentRequestContactInfoEditorTest, HappyPath) {
EXPECT_EQ(base::ASCIIToUTF16(kNameFull),
profile->GetInfo(autofill::AutofillType(autofill::NAME_FULL),
GetLocale()));
EXPECT_EQ(base::ASCIIToUTF16(kPhoneNumber),
EXPECT_EQ(base::ASCIIToUTF16("16515558946"),
profile->GetInfo(
autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
GetLocale()));
......@@ -108,7 +108,7 @@ IN_PROC_BROWSER_TEST_F(PaymentRequestContactInfoEditorTest,
EXPECT_EQ(base::ASCIIToUTF16(kNameFull),
profile->GetInfo(autofill::AutofillType(autofill::NAME_FULL),
GetLocale()));
EXPECT_EQ(base::ASCIIToUTF16(kPhoneNumber),
EXPECT_EQ(base::ASCIIToUTF16("16515558946"),
profile->GetInfo(
autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
GetLocale()));
......@@ -161,7 +161,7 @@ IN_PROC_BROWSER_TEST_F(PaymentRequestContactInfoEditorTest, Validation) {
EXPECT_EQ(base::ASCIIToUTF16(kNameFull),
profile->GetInfo(autofill::AutofillType(autofill::NAME_FULL),
GetLocale()));
EXPECT_EQ(base::ASCIIToUTF16(kPhoneNumber),
EXPECT_EQ(base::ASCIIToUTF16("16515558946"),
profile->GetInfo(
autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
GetLocale()));
......@@ -209,7 +209,7 @@ IN_PROC_BROWSER_TEST_F(PaymentRequestContactInfoEditorTest, ModifyExisting) {
EXPECT_EQ(base::ASCIIToUTF16(kNameFull),
profile->GetInfo(autofill::AutofillType(autofill::NAME_FULL),
GetLocale()));
EXPECT_EQ(base::ASCIIToUTF16(kPhoneNumber),
EXPECT_EQ(base::ASCIIToUTF16("16515558946"),
profile->GetInfo(
autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
GetLocale()));
......@@ -262,7 +262,7 @@ IN_PROC_BROWSER_TEST_F(PaymentRequestContactInfoEditorTest,
request->state()->selected_contact_profile();
DCHECK(profile);
EXPECT_EQ(base::ASCIIToUTF16(kPhoneNumber),
EXPECT_EQ(base::ASCIIToUTF16("16515558946"),
profile->GetInfo(
autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
GetLocale()));
......
......@@ -451,6 +451,23 @@ ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
~ShippingAddressValidationDelegate() {}
bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
ShouldFormat() {
return field_.type == autofill::PHONE_HOME_WHOLE_NUMBER;
}
base::string16
ShippingAddressEditorViewController::ShippingAddressValidationDelegate::Format(
const base::string16& text) {
if (controller_->chosen_country_index_ < controller_->countries_.size()) {
return base::UTF8ToUTF16(data_util::FormatPhoneForDisplay(
base::UTF16ToUTF8(text),
controller_->countries_[controller_->chosen_country_index_].first));
} else {
return text;
}
}
bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
IsValidTextfield(views::Textfield* textfield) {
return ValidateValue(textfield->text(), nullptr);
......
......@@ -71,6 +71,8 @@ class ShippingAddressEditorViewController : public EditorViewController {
~ShippingAddressValidationDelegate() override;
// ValidationDelegate:
bool ShouldFormat() override;
base::string16 Format(const base::string16& text) override;
bool IsValidTextfield(views::Textfield* textfield) override;
bool IsValidCombobox(views::Combobox* combobox) override;
bool TextfieldValueChanged(views::Textfield* textfield) override;
......
......@@ -31,8 +31,7 @@ const char kNameFull[] = "Bob Jones";
const char kHomeAddress[] = "42 Answers-All Avenue";
const char kHomeCity[] = "Question-City";
const char kHomeZip[] = "ziiiiiip";
const char kHomePhone[] = "5755555555"; // 5555555555 is invalid :-(.
const char kFormattedHomePhone[] = "(575) 555-5555";
const char kHomePhone[] = "+1 575-555-5555"; // +1 555-555-5555 is invalid :-(.
const char kAnyState[] = "any state";
const char kCountryWithoutStates[] = "Albania";
const char kCountryWithoutStatesPhoneNumber[] = "42223446";
......@@ -141,12 +140,10 @@ class PaymentRequestShippingAddressEditorTest
// The phone can be empty when restored from a saved state, or it may be
// formatted based on the currently selected country.
if (!accept_empty_phone_number) {
EXPECT_EQ(base::ASCIIToUTF16(kHomePhone), textfield_text);
EXPECT_EQ(base::ASCIIToUTF16("+1 575-555-5555"), textfield_text);
} else if (textfield_text.empty()) {
if (unset_types)
unset_types->insert(autofill::PHONE_HOME_WHOLE_NUMBER);
} else if (textfield_text != base::ASCIIToUTF16(kHomePhone)) {
EXPECT_EQ(base::ASCIIToUTF16(kFormattedHomePhone), textfield_text);
}
} else if (unset_types) {
unset_types->insert(autofill::PHONE_HOME_WHOLE_NUMBER);
......
......@@ -24,6 +24,9 @@ void ValidatingTextfield::OnBlur() {
was_blurred_ = true;
Validate();
}
if (!text().empty() && delegate_->ShouldFormat())
SetText(delegate_->Format(text()));
}
void ValidatingTextfield::ViewHierarchyChanged(
......@@ -33,6 +36,11 @@ void ValidatingTextfield::ViewHierarchyChanged(
}
void ValidatingTextfield::OnContentsChanged() {
if (!text().empty() && GetCursorPosition() == text().length() &&
delegate_->ShouldFormat()) {
SetText(delegate_->Format(text()));
}
// Validation on every keystroke only happens if the field has been validated
// before as part of a blur.
if (!was_blurred_)
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/payments/validation_delegate.h"
#include "base/logging.h"
namespace payments {
ValidationDelegate::~ValidationDelegate() {}
bool ValidationDelegate::ShouldFormat() {
return false;
}
base::string16 ValidationDelegate::Format(const base::string16& text) {
NOTREACHED();
return text;
}
} // namespace payments
......@@ -5,6 +5,8 @@
#ifndef CHROME_BROWSER_UI_VIEWS_PAYMENTS_VALIDATION_DELEGATE_H_
#define CHROME_BROWSER_UI_VIEWS_PAYMENTS_VALIDATION_DELEGATE_H_
#include "base/strings/string16.h"
namespace views {
class Combobox;
class Textfield;
......@@ -12,9 +14,13 @@ class Textfield;
namespace payments {
// Handles text field validation and formatting.
class ValidationDelegate {
public:
virtual ~ValidationDelegate() {}
virtual ~ValidationDelegate();
virtual bool ShouldFormat();
virtual base::string16 Format(const base::string16& text);
// Only the delegate knows how to validate the input fields.
virtual bool IsValidTextfield(views::Textfield* textfield) = 0;
......
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