Commit 54d4cbfc authored by Mathieu Perreault's avatar Mathieu Perreault Committed by Commit Bot

[Settings] Split Autofill settings into addresses and payments sections

Creates a new payments_section.html/js (credit cards for now).

With Autofill Home disabled, will add a new row in the Advanced Passwords and Forms
section to go to the credit cards section. There used to be one general Autofill
row that had both addresses and credit cards.

With Autofill Home enabled, the "Payments" row on the People page will now lead
to a payments-only section, and the "Addresses" row will lead to its own section
as well.

This is one change of several that will also clean up the settings toggle to
hopefully have a clearer story.

Screenshots of the change: https://goo.gl/iZWkCE (internal)

Bug: 860526
Test: browser_tests
Change-Id: I7572ccc71633ee806b4a5db522a64e2b4f79d5dc
Reviewed-on: https://chromium-review.googlesource.com/1152475
Commit-Queue: Mathieu Perreault <mathp@chromium.org>
Reviewed-by: default avatarDemetrios Papadopoulos <dpapad@chromium.org>
Cr-Commit-Position: refs/heads/master@{#579779}
parent cedc263f
...@@ -622,8 +622,8 @@ ...@@ -622,8 +622,8 @@
Autofill settings Autofill settings
</message> </message>
<!-- TODO(https://crbug.com/854562): Rename this to "IDS_SETTINGS_AUTOFILL" once Autofill Home is fully launched. --> <!-- TODO(https://crbug.com/854562): Rename this to "IDS_SETTINGS_AUTOFILL" once Autofill Home is fully launched. -->
<message name="IDS_SETTINGS_AUTOFILL_AUTOFILL_HOME" desc="Name for the addresses and payment methods section used for Autofill Home."> <message name="IDS_SETTINGS_AUTOFILL_AUTOFILL_HOME" desc="Name for the addresses section used for Autofill Home.">
Addresses &amp; payment methods Addresses
</message> </message>
<message name="IDS_SETTINGS_GOOGLE_PAYMENTS" desc="Label used to differentiate when an address or credit card entry comes from Google Pay. This should follow the casing of the 'Google Pay' brand. 'Google Pay' should not be translated as it is the product name."> <message name="IDS_SETTINGS_GOOGLE_PAYMENTS" desc="Label used to differentiate when an address or credit card entry comes from Google Pay. This should follow the casing of the 'Google Pay' brand. 'Google Pay' should not be translated as it is the product name.">
Google Pay Google Pay
...@@ -655,9 +655,13 @@ ...@@ -655,9 +655,13 @@
<message name="IDS_SETTINGS_AUTOFILL_ADDRESSES_EMAIL" desc="This is the label for the field that lets a user modify the email address that will be used when auto-filling forms on the web."> <message name="IDS_SETTINGS_AUTOFILL_ADDRESSES_EMAIL" desc="This is the label for the field that lets a user modify the email address that will be used when auto-filling forms on the web.">
Email Email
</message> </message>
<!-- TODO(https://crbug.com/854562): Remove this string (and use "IDS_SETTINGS_AUTOFILL_PAYMENT_METHODS" instead) once Autofill Home is fully launched. --> <!-- TODO(https://crbug.com/854562): Remove this string once Autofill Home is fully launched. -->
<message name="IDS_SETTINGS_AUTOFILL_CREDIT_CARD_HEADING" desc="Title for the list of saved passwords that can be used to fill in forms."> <message name="IDS_SETTINGS_AUTOFILL_CREDIT_CARD_HEADING" desc="Title for the list of saved passwords that can be used to fill in forms.">
Credit cards Credit card settings
</message>
<!-- TODO(https://crbug.com/854562): Remove this string once Autofill Home is fully launched. -->
<message name="IDS_SETTINGS_AUTOFILL_CREDIT_CARD_DETAIL" desc="Description of what toggling the 'Credit card' setting does. Immediately underneath IDS_SETTINGS_AUTOFILL_CREDIT_CARD_HEADING.">
Enable credit card Autofill to fill out forms in a single click
</message> </message>
<message name="IDS_SETTINGS_AUTOFILL_PAYMENT_METHODS" desc="Title for the list of saved payment methods that can be used to fill in forms."> <message name="IDS_SETTINGS_AUTOFILL_PAYMENT_METHODS" desc="Title for the list of saved payment methods that can be used to fill in forms.">
Payment methods Payment methods
......
...@@ -14,6 +14,7 @@ js_type_check("closure_compile") { ...@@ -14,6 +14,7 @@ js_type_check("closure_compile") {
":password_manager_proxy", ":password_manager_proxy",
":passwords_and_forms_page", ":passwords_and_forms_page",
":passwords_section", ":passwords_section",
":payments_section",
":show_password_behavior", ":show_password_behavior",
] ]
} }
...@@ -22,6 +23,7 @@ js_library("passwords_and_forms_page") { ...@@ -22,6 +23,7 @@ js_library("passwords_and_forms_page") {
deps = [ deps = [
":autofill_section", ":autofill_section",
":passwords_section", ":passwords_section",
":payments_section",
"..:route", "..:route",
"../prefs:prefs_behavior", "../prefs:prefs_behavior",
"../settings_page:settings_animated_pages", "../settings_page:settings_animated_pages",
...@@ -37,10 +39,20 @@ js_library("passwords_and_forms_page") { ...@@ -37,10 +39,20 @@ js_library("passwords_and_forms_page") {
js_library("autofill_section") { js_library("autofill_section") {
deps = [ deps = [
":address_edit_dialog", ":address_edit_dialog",
"//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu",
"//ui/webui/resources/js:assert",
"//ui/webui/resources/js:load_time_data",
"//ui/webui/resources/js/cr/ui:focus_without_ink",
]
externs_list = [ "$externs_path/autofill_private.js" ]
}
js_library("payments_section") {
deps = [
":credit_card_edit_dialog", ":credit_card_edit_dialog",
"//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu", "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu",
"//ui/webui/resources/js:assert", "//ui/webui/resources/js:assert",
"//ui/webui/resources/js:i18n_behavior", "//ui/webui/resources/js:load_time_data",
"//ui/webui/resources/js/cr/ui:focus_without_ink", "//ui/webui/resources/js/cr/ui:focus_without_ink",
] ]
externs_list = [ "$externs_path/autofill_private.js" ] externs_list = [ "$externs_path/autofill_private.js" ]
......
<link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html"> <link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html">
<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html">
<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
<link rel="import" href="chrome://resources/html/action_link.html">
<link rel="import" href="chrome://resources/html/action_link_css.html">
<link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="chrome://resources/html/assert.html">
<link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html"> <link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
<link rel="import" href="../i18n_setup.html"> <link rel="import" href="../i18n_setup.html">
<link rel="import" href="../settings_shared_css.html"> <link rel="import" href="../settings_shared_css.html">
...@@ -15,32 +10,11 @@ ...@@ -15,32 +10,11 @@
<link rel="import" href="../controls/settings_toggle_button.html"> <link rel="import" href="../controls/settings_toggle_button.html">
<link rel="import" href="../prefs/prefs.html"> <link rel="import" href="../prefs/prefs.html">
<link rel="import" href="address_edit_dialog.html"> <link rel="import" href="address_edit_dialog.html">
<link rel="import" href="credit_card_edit_dialog.html">
<link rel="import" href="passwords_shared_css.html"> <link rel="import" href="passwords_shared_css.html">
<dom-module id="settings-autofill-section"> <dom-module id="settings-autofill-section">
<template> <template>
<style include="settings-shared passwords-shared action-link"> <style include="settings-shared passwords-shared">
.type-column {
align-items: center;
flex: 2;
}
.expiration-column {
align-items: center;
display: flex;
flex: 1;
}
.expiration-date {
flex: 1;
}
.payments-label {
color: var(--cr-secondary-text-color);
margin-inline-start: 16px;
}
#addressList .start { #addressList .start {
display: flex; display: flex;
overflow: hidden; overflow: hidden;
...@@ -51,19 +25,6 @@ ...@@ -51,19 +25,6 @@
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
} }
.ellipses {
flex: 1;
max-width: fit-content;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
cr-policy-indicator {
padding-right: 20px;
width: 20px;
}
</style> </style>
<settings-toggle-button id="autofillToggle" <settings-toggle-button id="autofillToggle"
class="first" class="first"
...@@ -112,9 +73,6 @@ ...@@ -112,9 +73,6 @@
[[item.metadata.summarySublabel]] [[item.metadata.summarySublabel]]
</span> </span>
</span> </span>
<span class="payments-label" hidden$="[[item.metadata.isLocal]]">
$i18n{googlePayments}
</span>
</div> </div>
<template is="dom-if" if="[[item.metadata.isLocal]]"> <template is="dom-if" if="[[item.metadata.isLocal]]">
<paper-icon-button-light class="icon-more-vert"> <paper-icon-button-light class="icon-more-vert">
...@@ -144,90 +102,9 @@ ...@@ -144,90 +102,9 @@
</cr-action-menu> </cr-action-menu>
<template is="dom-if" if="[[showAddressDialog_]]" restamp> <template is="dom-if" if="[[showAddressDialog_]]" restamp>
<settings-address-edit-dialog address="[[activeAddress]]" <settings-address-edit-dialog address="[[activeAddress]]"
on-close="onAddressDialogClosed_"> on-close="onAddressDialogClose_">
</settings-address-edit-dialog> </settings-address-edit-dialog>
</template> </template>
<settings-toggle-button id="autofillCreditCardToggle"
class="settings-box first"
aria-label="$i18n{autofill}" no-extension-indicator
label="$i18n{enableCreditCardsLabel}"
pref="{{prefs.autofill.credit_card_enabled}}"
disabled$="[[!prefs.autofill.enabled.value]]">
</settings-toggle-button>
<div class="settings-box continuation">
<h2 class="start">$i18n{creditCards}</h2>
<paper-button id="addCreditCard"
class="secondary-button header-aligned-button"
on-click="onAddCreditCardTap_"
disabled$="[[eitherIsDisabled_(prefs.autofill.enabled.value,
prefs.autofill.credit_card_enabled.value)]]">
$i18n{add}
</paper-button>
</div>
<div class="list-frame">
<div id="creditCardsHeading" class="list-item column-header"
hidden$="[[!hasSome_(creditCards)]]">
<div class="type-column">$i18n{creditCardType}</div>
<div class="expiration-column">$i18n{creditCardExpiration}</div>
</div>
<div id="creditCardList" class="vertical-list list-with-header">
<template is="dom-repeat" items="[[creditCards]]">
<div class="list-item">
<div class="type-column">
<span id="creditCardLabel">[[item.metadata.summaryLabel]]</span>
<span class="payments-label"
hidden$="[[item.metadata.isLocal]]">
<span hidden$="[[item.metadata.isCached]]">
$i18n{googlePayments}
</span>
<span hidden$="[[!item.metadata.isCached]]">
$i18n{googlePaymentsCached}
</span>
</span>
</div>
<div class="expiration-column">
<div id="creditCardExpiration"
class="expiration-date">[[expiration_(item)]]</div>
<template is="dom-if" if="[[showDots_(item.metadata)]]">
<paper-icon-button-light class="icon-more-vert">
<button id="creditCardMenu" title="$i18n{moreActions}"
on-click="onCreditCardMenuTap_">
</button>
</paper-icon-button-light>
</template>
<template is="dom-if" if="[[!showDots_(item.metadata)]]">
<paper-icon-button-light actionable class="icon-external">
<button id="remoteCreditCardLink"
on-click="onRemoteEditCreditCardTap_">
</button>
</paper-icon-button-light>
</template>
</div>
</div>
</template>
</div>
<div id="noCreditCardsLabel" class="list-item"
hidden$="[[hasSome_(creditCards)]]">
$i18n{noCreditCardsFound}
</div>
</div>
<cr-action-menu id="creditCardSharedMenu">
<button id="menuEditCreditCard" slot="item" class="dropdown-item"
on-click="onMenuEditCreditCardTap_">$i18n{edit}</button>
<button id="menuRemoveCreditCard" slot="item" class="dropdown-item"
hidden$="[[!activeCreditCard.metadata.isLocal]]"
on-click="onMenuRemoveCreditCardTap_">$i18n{removeCreditCard}</button>
<button id="menuClearCreditCard" slot="item" class="dropdown-item"
on-click="onMenuClearCreditCardTap_"
hidden$="[[!activeCreditCard.metadata.isCached]]">
$i18n{clearCreditCard}
</button>
</cr-action-menu>
<template is="dom-if" if="[[showCreditCardDialog_]]" restamp>
<settings-credit-card-edit-dialog credit-card="[[activeCreditCard]]"
on-close="onCreditCardDialogClosed_">
</settings-credit-card-edit-dialog>
</template>
</template> </template>
<script src="autofill_section.js"></script> <script src="autofill_section.js"></script>
</dom-module> </dom-module>
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
/** /**
* @fileoverview 'settings-autofill-section' is the section containing saved * @fileoverview 'settings-autofill-section' is the section containing saved
* addresses and credit cards for use in autofill. * addresses for use in autofill and payments APIs.
*/ */
/** /**
...@@ -38,44 +38,11 @@ class AutofillManager { ...@@ -38,44 +38,11 @@ class AutofillManager {
/** @param {string} guid The guid of the address to remove. */ /** @param {string} guid The guid of the address to remove. */
removeAddress(guid) {} removeAddress(guid) {}
/**
* Add an observer to the list of credit cards.
* @param {function(!Array<!AutofillManager.CreditCardEntry>):void} listener
*/
addCreditCardListChangedListener(listener) {}
/**
* Remove an observer from the list of credit cards.
* @param {function(!Array<!AutofillManager.CreditCardEntry>):void} listener
*/
removeCreditCardListChangedListener(listener) {}
/**
* Request the list of credit cards.
* @param {function(!Array<!AutofillManager.CreditCardEntry>):void} callback
*/
getCreditCardList(callback) {}
/** @param {string} guid The GUID of the credit card to remove. */
removeCreditCard(guid) {}
/** @param {string} guid The GUID to credit card to remove from the cache. */
clearCachedCreditCard(guid) {}
/**
* Saves the given credit card.
* @param {!AutofillManager.CreditCardEntry} creditCard
*/
saveCreditCard(creditCard) {}
} }
/** @typedef {chrome.autofillPrivate.AddressEntry} */ /** @typedef {chrome.autofillPrivate.AddressEntry} */
AutofillManager.AddressEntry; AutofillManager.AddressEntry;
/** @typedef {chrome.autofillPrivate.CreditCardEntry} */
AutofillManager.CreditCardEntry;
/** /**
* Implementation that accesses the private API. * Implementation that accesses the private API.
* @implements {AutofillManager} * @implements {AutofillManager}
...@@ -105,36 +72,6 @@ class AutofillManagerImpl { ...@@ -105,36 +72,6 @@ class AutofillManagerImpl {
removeAddress(guid) { removeAddress(guid) {
chrome.autofillPrivate.removeEntry(assert(guid)); chrome.autofillPrivate.removeEntry(assert(guid));
} }
/** @override */
addCreditCardListChangedListener(listener) {
chrome.autofillPrivate.onCreditCardListChanged.addListener(listener);
}
/** @override */
removeCreditCardListChangedListener(listener) {
chrome.autofillPrivate.onCreditCardListChanged.removeListener(listener);
}
/** @override */
getCreditCardList(callback) {
chrome.autofillPrivate.getCreditCardList(callback);
}
/** @override */
removeCreditCard(guid) {
chrome.autofillPrivate.removeEntry(assert(guid));
}
/** @override */
clearCachedCreditCard(guid) {
chrome.autofillPrivate.maskCreditCard(assert(guid));
}
/** @override */
saveCreditCard(creditCard) {
chrome.autofillPrivate.saveCreditCard(creditCard);
}
} }
cr.addSingletonGetter(AutofillManagerImpl); cr.addSingletonGetter(AutofillManagerImpl);
...@@ -145,8 +82,6 @@ cr.addSingletonGetter(AutofillManagerImpl); ...@@ -145,8 +82,6 @@ cr.addSingletonGetter(AutofillManagerImpl);
Polymer({ Polymer({
is: 'settings-autofill-section', is: 'settings-autofill-section',
behaviors: [I18nBehavior],
properties: { properties: {
/** /**
* An array of saved addresses. * An array of saved addresses.
...@@ -162,26 +97,10 @@ Polymer({ ...@@ -162,26 +97,10 @@ Polymer({
/** @private */ /** @private */
showAddressDialog_: Boolean, showAddressDialog_: Boolean,
/**
* An array of saved credit cards.
* @type {!Array<!AutofillManager.CreditCardEntry>}
*/
creditCards: Array,
/**
* The model for any credit card related action menus or dialogs.
* @private {?chrome.autofillPrivate.CreditCardEntry}
*/
activeCreditCard: Object,
/** @private */
showCreditCardDialog_: Boolean,
}, },
listeners: { listeners: {
'save-address': 'saveAddress_', 'save-address': 'saveAddress_',
'save-credit-card': 'saveCreditCard_',
}, },
/** /**
...@@ -203,12 +122,6 @@ Polymer({ ...@@ -203,12 +122,6 @@ Polymer({
*/ */
setAddressesListener_: null, setAddressesListener_: null,
/**
* @type {?function(!Array<!AutofillManager.CreditCardEntry>)}
* @private
*/
setCreditCardsListener_: null,
/** @override */ /** @override */
attached: function() { attached: function() {
// Create listener functions. // Create listener functions.
...@@ -217,26 +130,17 @@ Polymer({ ...@@ -217,26 +130,17 @@ Polymer({
this.addresses = list; this.addresses = list;
}; };
/** @type {function(!Array<!AutofillManager.CreditCardEntry>)} */
const setCreditCardsListener = list => {
this.creditCards = list;
};
// Remember the bound reference in order to detach. // Remember the bound reference in order to detach.
this.setAddressesListener_ = setAddressesListener; this.setAddressesListener_ = setAddressesListener;
this.setCreditCardsListener_ = setCreditCardsListener;
// Set the managers. These can be overridden by tests. // Set the managers. These can be overridden by tests.
this.autofillManager_ = AutofillManagerImpl.getInstance(); this.autofillManager_ = AutofillManagerImpl.getInstance();
// Request initial data. // Request initial data.
this.autofillManager_.getAddressList(setAddressesListener); this.autofillManager_.getAddressList(setAddressesListener);
this.autofillManager_.getCreditCardList(setCreditCardsListener);
// Listen for changes. // Listen for changes.
this.autofillManager_.addAddressListChangedListener(setAddressesListener); this.autofillManager_.addAddressListChangedListener(setAddressesListener);
this.autofillManager_.addCreditCardListChangedListener(
setCreditCardsListener);
}, },
/** @override */ /** @override */
...@@ -244,19 +148,6 @@ Polymer({ ...@@ -244,19 +148,6 @@ Polymer({
this.autofillManager_.removeAddressListChangedListener( this.autofillManager_.removeAddressListChangedListener(
/** @type {function(!Array<!AutofillManager.AddressEntry>)} */ ( /** @type {function(!Array<!AutofillManager.AddressEntry>)} */ (
this.setAddressesListener_)); this.setAddressesListener_));
this.autofillManager_.removeCreditCardListChangedListener(
/** @type {function(!Array<!AutofillManager.CreditCardEntry>)} */ (
this.setCreditCardsListener_));
},
/**
* Formats the expiration date so it's displayed as MM/YYYY.
* @param {!chrome.autofillPrivate.CreditCardEntry} item
* @return {string}
* @private
*/
expiration_: function(item) {
return item.expirationMonth + '/' + item.expirationYear;
}, },
/** /**
...@@ -297,7 +188,7 @@ Polymer({ ...@@ -297,7 +188,7 @@ Polymer({
}, },
/** @private */ /** @private */
onAddressDialogClosed_: function() { onAddressDialogClose_: function() {
this.showAddressDialog_ = false; this.showAddressDialog_ = false;
cr.ui.focusWithoutInk(assert(this.activeDialogAnchor_)); cr.ui.focusWithoutInk(assert(this.activeDialogAnchor_));
this.activeDialogAnchor_ = null; this.activeDialogAnchor_ = null;
...@@ -316,7 +207,7 @@ Polymer({ ...@@ -316,7 +207,7 @@ Polymer({
/** @private */ /** @private */
onRemoteEditAddressTap_: function() { onRemoteEditAddressTap_: function() {
window.open(this.i18n('manageAddressesUrl')); window.open(loadTimeData.getString('manageAddressesUrl'));
}, },
/** /**
...@@ -329,107 +220,6 @@ Polymer({ ...@@ -329,107 +220,6 @@ Polymer({
this.$.addressSharedMenu.close(); this.$.addressSharedMenu.close();
}, },
/**
* Opens the credit card action menu.
* @param {!Event} e The polymer event.
* @private
*/
onCreditCardMenuTap_: function(e) {
const menuEvent = /** @type {!{model: !{item: !Object}}} */ (e);
/* TODO(scottchen): drop the [dataHost][dataHost] once this bug is fixed:
https://github.com/Polymer/polymer/issues/2574 */
// TODO(dpapad): The [dataHost][dataHost] workaround is only necessary for
// Polymer 1. Remove once migration to Polymer 2 has completed.
const item = Polymer.DomIf ? menuEvent.model.item :
menuEvent.model['dataHost']['dataHost'].item;
// Copy item so dialog won't update model on cancel.
this.activeCreditCard =
/** @type {!chrome.autofillPrivate.CreditCardEntry} */ (
Object.assign({}, item));
const dotsButton = /** @type {!HTMLElement} */ (Polymer.dom(e).localTarget);
/** @type {!CrActionMenuElement} */ (this.$.creditCardSharedMenu)
.showAt(dotsButton);
this.activeDialogAnchor_ = dotsButton;
},
/**
* Handles tapping on the "Add credit card" button.
* @param {!Event} e
* @private
*/
onAddCreditCardTap_: function(e) {
e.preventDefault();
const date = new Date(); // Default to current month/year.
const expirationMonth = date.getMonth() + 1; // Months are 0 based.
this.activeCreditCard = {
expirationMonth: expirationMonth.toString(),
expirationYear: date.getFullYear().toString(),
};
this.showCreditCardDialog_ = true;
this.activeDialogAnchor_ = this.$.addCreditCard;
},
/** @private */
onCreditCardDialogClosed_: function() {
this.showCreditCardDialog_ = false;
cr.ui.focusWithoutInk(assert(this.activeDialogAnchor_));
this.activeDialogAnchor_ = null;
},
/**
* Handles tapping on the "Edit" credit card button.
* @param {!Event} e The polymer event.
* @private
*/
onMenuEditCreditCardTap_: function(e) {
e.preventDefault();
if (this.activeCreditCard.metadata.isLocal)
this.showCreditCardDialog_ = true;
else
this.onRemoteEditCreditCardTap_();
this.$.creditCardSharedMenu.close();
},
/** @private */
onRemoteEditCreditCardTap_: function() {
window.open(this.i18n('manageCreditCardsUrl'));
},
/**
* Handles tapping on the "Remove" credit card button.
* @private
*/
onMenuRemoveCreditCardTap_: function() {
this.autofillManager_.removeCreditCard(
/** @type {string} */ (this.activeCreditCard.guid));
this.$.creditCardSharedMenu.close();
},
/**
* Handles tapping on the "Clear copy" button for cached credit cards.
* @private
*/
onMenuClearCreditCardTap_: function() {
this.autofillManager_.clearCachedCreditCard(
/** @type {string} */ (this.activeCreditCard.guid));
this.$.creditCardSharedMenu.close();
},
/**
* The 3-dot menu should not be shown if the card is entirely remote.
* @param {!chrome.autofillPrivate.AutofillMetadata} metadata
* @return {boolean}
* @private
*/
showDots_: function(metadata) {
return !!(metadata.isLocal || metadata.isCached);
},
/** /**
* Returns true if the list exists and has items. * Returns true if the list exists and has items.
* @param {Array<Object>} list * @param {Array<Object>} list
...@@ -459,23 +249,5 @@ Polymer({ ...@@ -459,23 +249,5 @@ Polymer({
saveAddress_: function(event) { saveAddress_: function(event) {
this.autofillManager_.saveAddress(event.detail); this.autofillManager_.saveAddress(event.detail);
}, },
/**
* Listens for the save-credit-card event, and calls the private API.
* @param {!Event} event
* @private
*/
saveCreditCard_: function(event) {
this.autofillManager_.saveCreditCard(event.detail);
},
/**
* @private
* @param {boolean} toggleValue
* @return {string}
*/
getOnOffLabel_: function(toggleValue) {
return toggleValue ? this.i18n('toggleOn') : this.i18n('toggleOff');
}
}); });
})(); })();
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
<link rel="import" href="autofill_section.html"> <link rel="import" href="autofill_section.html">
<link rel="import" href="passwords_section.html"> <link rel="import" href="passwords_section.html">
<link rel="import" href="payments_section.html">
<link rel="import" href="../controls/extension_controlled_indicator.html"> <link rel="import" href="../controls/extension_controlled_indicator.html">
<link rel="import" href="../controls/settings_toggle_button.html"> <link rel="import" href="../controls/settings_toggle_button.html">
<link rel="import" href="../prefs/prefs.html"> <link rel="import" href="../prefs/prefs.html">
...@@ -27,6 +28,10 @@ ...@@ -27,6 +28,10 @@
id="autofillManagerButton" label="$i18n{autofill}" id="autofillManagerButton" label="$i18n{autofill}"
sub-label="$i18n{autofillDetail}" on-click="onAutofillTap_"> sub-label="$i18n{autofillDetail}" on-click="onAutofillTap_">
</cr-link-row> </cr-link-row>
<cr-link-row icon-class="subpage-arrow"
id="paymentManagerButton" label="$i18n{creditCards}"
sub-label="$i18n{creditCardsDetail}" on-click="onPaymentsTap_">
</cr-link-row>
<div class="settings-box two-line"> <div class="settings-box two-line">
<div class="start two-line" on-click="onPasswordsTap_" actionable <div class="start two-line" on-click="onPasswordsTap_" actionable
id="passwordManagerButton"> id="passwordManagerButton">
...@@ -51,6 +56,14 @@ ...@@ -51,6 +56,14 @@
</settings-autofill-section> </settings-autofill-section>
</settings-subpage> </settings-subpage>
</template> </template>
<template is="dom-if" route-path="/payments">
<settings-subpage
associated-control="[[$$('#paymentManagerButton')]]"
page-title="$i18n{creditCards}">
<settings-payments-section id="paymentSection" prefs="{{prefs}}">
</settings-payments-section>
</settings-subpage>
</template>
<template is="dom-if" route-path="/passwords"> <template is="dom-if" route-path="/passwords">
<settings-subpage <settings-subpage
associated-control="[[$$('#passwordManagerButton')]]" associated-control="[[$$('#passwordManagerButton')]]"
......
...@@ -38,12 +38,19 @@ Polymer({ ...@@ -38,12 +38,19 @@ Polymer({
settings.navigateTo(settings.routes.AUTOFILL); settings.navigateTo(settings.routes.AUTOFILL);
}, },
/**
* Shows the manage payment methods sub page.
* @private
*/
onPaymentsTap_: function() {
settings.navigateTo(settings.routes.PAYMENTS);
},
/** /**
* Shows the manage passwords sub page. * Shows the manage passwords sub page.
* @param {!Event} event
* @private * @private
*/ */
onPasswordsTap_: function(event) { onPasswordsTap_: function() {
settings.navigateTo(settings.routes.MANAGE_PASSWORDS); settings.navigateTo(settings.routes.MANAGE_PASSWORDS);
}, },
}); });
...@@ -34,6 +34,19 @@ ...@@ -34,6 +34,19 @@
height: 20px; height: 20px;
width: 0; width: 0;
} }
.type-column {
align-items: center;
flex: 2;
}
.ellipses {
flex: 1;
max-width: fit-content;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style> </style>
</template> </template>
</dom-module> </dom-module>
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html">
<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
<link rel="import" href="chrome://resources/html/assert.html">
<link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
<link rel="import" href="../i18n_setup.html">
<link rel="import" href="../settings_shared_css.html">
<link rel="import" href="../controls/settings_toggle_button.html">
<link rel="import" href="../prefs/prefs.html">
<link rel="import" href="credit_card_edit_dialog.html">
<link rel="import" href="passwords_shared_css.html">
<dom-module id="settings-payments-section">
<template>
<style include="settings-shared passwords-shared">
.expiration-column {
align-items: center;
display: flex;
flex: 1;
}
.expiration-date {
flex: 1;
}
.payments-label {
color: var(--cr-secondary-text-color);
margin-inline-start: 16px;
}
</style>
<settings-toggle-button id="autofillCreditCardToggle"
class="settings-box first"
aria-label="$i18n{creditCards}" no-extension-indicator
label="$i18n{enableCreditCardsLabel}"
pref="{{prefs.autofill.credit_card_enabled}}"
disabled$="[[!prefs.autofill.enabled.value]]">
</settings-toggle-button>
<div class="settings-box continuation">
<h2 class="start">$i18n{creditCards}</h2>
<paper-button id="addCreditCard"
class="secondary-button header-aligned-button"
on-click="onAddCreditCardTap_"
disabled$="[[eitherIsDisabled_(prefs.autofill.enabled.value,
prefs.autofill.credit_card_enabled.value)]]">
$i18n{add}
</paper-button>
</div>
<div class="list-frame">
<div id="creditCardsHeading" class="list-item column-header"
hidden$="[[!hasSome_(creditCards)]]">
<div class="type-column">$i18n{creditCardType}</div>
<div class="expiration-column">$i18n{creditCardExpiration}</div>
</div>
<div id="creditCardList" class="vertical-list list-with-header">
<template is="dom-repeat" items="[[creditCards]]">
<div class="list-item">
<div class="type-column">
<span id="creditCardLabel">[[item.metadata.summaryLabel]]</span>
<span class="payments-label"
hidden$="[[item.metadata.isLocal]]">
<span hidden$="[[item.metadata.isCached]]">
$i18n{googlePayments}
</span>
<span hidden$="[[!item.metadata.isCached]]">
$i18n{googlePaymentsCached}
</span>
</span>
</div>
<div class="expiration-column">
<div id="creditCardExpiration"
class="expiration-date">[[expiration_(item)]]</div>
<template is="dom-if" if="[[showDots_(item.metadata)]]">
<paper-icon-button-light class="icon-more-vert">
<button id="creditCardMenu" title="$i18n{moreActions}"
on-click="onCreditCardMenuTap_">
</button>
</paper-icon-button-light>
</template>
<template is="dom-if" if="[[!showDots_(item.metadata)]]">
<paper-icon-button-light actionable class="icon-external">
<button id="remoteCreditCardLink"
on-click="onRemoteEditCreditCardTap_">
</button>
</paper-icon-button-light>
</template>
</div>
</div>
</template>
</div>
<div id="noCreditCardsLabel" class="list-item"
hidden$="[[hasSome_(creditCards)]]">
$i18n{noCreditCardsFound}
</div>
</div>
<cr-action-menu id="creditCardSharedMenu">
<button id="menuEditCreditCard" slot="item" class="dropdown-item"
on-click="onMenuEditCreditCardTap_">$i18n{edit}</button>
<button id="menuRemoveCreditCard" slot="item" class="dropdown-item"
hidden$="[[!activeCreditCard.metadata.isLocal]]"
on-click="onMenuRemoveCreditCardTap_">$i18n{removeCreditCard}</button>
<button id="menuClearCreditCard" slot="item" class="dropdown-item"
on-click="onMenuClearCreditCardTap_"
hidden$="[[!activeCreditCard.metadata.isCached]]">
$i18n{clearCreditCard}
</button>
</cr-action-menu>
<template is="dom-if" if="[[showCreditCardDialog_]]" restamp>
<settings-credit-card-edit-dialog credit-card="[[activeCreditCard]]"
on-close="onCreditCardDialogClose_">
</settings-credit-card-edit-dialog>
</template>
</template>
<script src="payments_section.js"></script>
</dom-module>
// Copyright 2018 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.
/**
* @fileoverview 'settings-payments-section' is the section containing saved
* credit cards for use in autofill and payments APIs.
*/
/**
* Interface for all callbacks to the payments autofill API.
* @interface
*/
class PaymentsManager {
/**
* Add an observer to the list of credit cards.
* @param {function(!Array<!PaymentsManager.CreditCardEntry>):void} listener
*/
addCreditCardListChangedListener(listener) {}
/**
* Remove an observer from the list of credit cards.
* @param {function(!Array<!PaymentsManager.CreditCardEntry>):void} listener
*/
removeCreditCardListChangedListener(listener) {}
/**
* Request the list of credit cards.
* @param {function(!Array<!PaymentsManager.CreditCardEntry>):void} callback
*/
getCreditCardList(callback) {}
/** @param {string} guid The GUID of the credit card to remove. */
removeCreditCard(guid) {}
/** @param {string} guid The GUID to credit card to remove from the cache. */
clearCachedCreditCard(guid) {}
/**
* Saves the given credit card.
* @param {!PaymentsManager.CreditCardEntry} creditCard
*/
saveCreditCard(creditCard) {}
}
/** @typedef {chrome.autofillPrivate.CreditCardEntry} */
PaymentsManager.CreditCardEntry;
/**
* Implementation that accesses the private API.
* @implements {PaymentsManager}
*/
class PaymentsManagerImpl {
/** @override */
addCreditCardListChangedListener(listener) {
chrome.autofillPrivate.onCreditCardListChanged.addListener(listener);
}
/** @override */
removeCreditCardListChangedListener(listener) {
chrome.autofillPrivate.onCreditCardListChanged.removeListener(listener);
}
/** @override */
getCreditCardList(callback) {
chrome.autofillPrivate.getCreditCardList(callback);
}
/** @override */
removeCreditCard(guid) {
chrome.autofillPrivate.removeEntry(assert(guid));
}
/** @override */
clearCachedCreditCard(guid) {
chrome.autofillPrivate.maskCreditCard(assert(guid));
}
/** @override */
saveCreditCard(creditCard) {
chrome.autofillPrivate.saveCreditCard(creditCard);
}
}
cr.addSingletonGetter(PaymentsManagerImpl);
(function() {
'use strict';
Polymer({
is: 'settings-payments-section',
properties: {
/**
* An array of saved credit cards.
* @type {!Array<!PaymentsManager.CreditCardEntry>}
*/
creditCards: Array,
/**
* The model for any credit card related action menus or dialogs.
* @private {?chrome.autofillPrivate.CreditCardEntry}
*/
activeCreditCard: Object,
/** @private */
showCreditCardDialog_: Boolean,
},
listeners: {
'save-credit-card': 'saveCreditCard_',
},
/**
* The element to return focus to, when the currently active dialog is
* closed.
* @private {?HTMLElement}
*/
activeDialogAnchor_: null,
/**
* @type {PaymentsManager}
* @private
*/
PaymentsManager_: null,
/**
* @type {?function(!Array<!PaymentsManager.CreditCardEntry>)}
* @private
*/
setCreditCardsListener_: null,
/** @override */
attached: function() {
// Create listener function.
/** @type {function(!Array<!PaymentsManager.CreditCardEntry>)} */
const setCreditCardsListener = list => {
this.creditCards = list;
};
// Remember the bound reference in order to detach.
this.setCreditCardsListener_ = setCreditCardsListener;
// Set the managers. These can be overridden by tests.
this.paymentsManager_ = PaymentsManagerImpl.getInstance();
// Request initial data.
this.paymentsManager_.getCreditCardList(setCreditCardsListener);
// Listen for changes.
this.paymentsManager_.addCreditCardListChangedListener(
setCreditCardsListener);
},
/** @override */
detached: function() {
this.paymentsManager_.removeCreditCardListChangedListener(
/** @type {function(!Array<!PaymentsManager.CreditCardEntry>)} */ (
this.setCreditCardsListener_));
},
/**
* Formats the expiration date so it's displayed as MM/YYYY.
* @param {!chrome.autofillPrivate.CreditCardEntry} item
* @return {string}
* @private
*/
expiration_: function(item) {
return item.expirationMonth + '/' + item.expirationYear;
},
/**
* Opens the credit card action menu.
* @param {!Event} e The polymer event.
* @private
*/
onCreditCardMenuTap_: function(e) {
const menuEvent = /** @type {!{model: !{item: !Object}}} */ (e);
/* TODO(scottchen): drop the [dataHost][dataHost] once this bug is fixed:
https://github.com/Polymer/polymer/issues/2574 */
// TODO(dpapad): The [dataHost][dataHost] workaround is only necessary for
// Polymer 1. Remove once migration to Polymer 2 has completed.
const item = Polymer.DomIf ? menuEvent.model.item :
menuEvent.model['dataHost']['dataHost'].item;
// Copy item so dialog won't update model on cancel.
this.activeCreditCard =
/** @type {!chrome.autofillPrivate.CreditCardEntry} */ (
Object.assign({}, item));
const dotsButton = /** @type {!HTMLElement} */ (Polymer.dom(e).localTarget);
/** @type {!CrActionMenuElement} */ (this.$.creditCardSharedMenu)
.showAt(dotsButton);
this.activeDialogAnchor_ = dotsButton;
},
/**
* Handles tapping on the "Add credit card" button.
* @param {!Event} e
* @private
*/
onAddCreditCardTap_: function(e) {
e.preventDefault();
const date = new Date(); // Default to current month/year.
const expirationMonth = date.getMonth() + 1; // Months are 0 based.
this.activeCreditCard = {
expirationMonth: expirationMonth.toString(),
expirationYear: date.getFullYear().toString(),
};
this.showCreditCardDialog_ = true;
this.activeDialogAnchor_ = this.$.addCreditCard;
},
/** @private */
onCreditCardDialogClose_: function() {
this.showCreditCardDialog_ = false;
cr.ui.focusWithoutInk(assert(this.activeDialogAnchor_));
this.activeDialogAnchor_ = null;
this.activeCreditCard = null;
},
/**
* Handles tapping on the "Edit" credit card button.
* @param {!Event} e The polymer event.
* @private
*/
onMenuEditCreditCardTap_: function(e) {
e.preventDefault();
if (this.activeCreditCard.metadata.isLocal)
this.showCreditCardDialog_ = true;
else
this.onRemoteEditCreditCardTap_();
this.$.creditCardSharedMenu.close();
},
/** @private */
onRemoteEditCreditCardTap_: function() {
window.open(loadTimeData.getString('manageCreditCardsUrl'));
},
/**
* Handles tapping on the "Remove" credit card button.
* @private
*/
onMenuRemoveCreditCardTap_: function() {
this.paymentsManager_.removeCreditCard(
/** @type {string} */ (this.activeCreditCard.guid));
this.$.creditCardSharedMenu.close();
this.activeCreditCard = null;
},
/**
* Handles tapping on the "Clear copy" button for cached credit cards.
* @private
*/
onMenuClearCreditCardTap_: function() {
this.paymentsManager_.clearCachedCreditCard(
/** @type {string} */ (this.activeCreditCard.guid));
this.$.creditCardSharedMenu.close();
this.activeCreditCard = null;
},
/**
* The 3-dot menu should not be shown if the card is entirely remote.
* @param {!chrome.autofillPrivate.AutofillMetadata} metadata
* @return {boolean}
* @private
*/
showDots_: function(metadata) {
return !!(metadata.isLocal || metadata.isCached);
},
/**
* Returns true if the list exists and has items.
* @param {Array<Object>} list
* @return {boolean}
* @private
*/
hasSome_: function(list) {
return !!(list && list.length);
},
/**
* Returns true if either pref value is false.
* @param {boolean} pref1Value
* @param {boolean} pref2Value
* @return {boolean}
* @private
*/
eitherIsDisabled_: function(pref1Value, pref2Value) {
return !pref1Value || !pref2Value;
},
/**
* Listens for the save-credit-card event, and calls the private API.
* @param {!Event} event
* @private
*/
saveCreditCard_: function(event) {
this.paymentsManager_.saveCreditCard(event.detail);
},
});
})();
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
<link rel="import" href="../settings_page/settings_subpage.html"> <link rel="import" href="../settings_page/settings_subpage.html">
<link rel="import" href="../passwords_and_forms_page/autofill_section.html"> <link rel="import" href="../passwords_and_forms_page/autofill_section.html">
<link rel="import" href="../passwords_and_forms_page/passwords_section.html"> <link rel="import" href="../passwords_and_forms_page/passwords_section.html">
<link rel="import" href="../passwords_and_forms_page/payments_section.html">
<link rel="import" href="../settings_shared_css.html"> <link rel="import" href="../settings_shared_css.html">
<if expr="chromeos"> <if expr="chromeos">
...@@ -290,7 +291,7 @@ ...@@ -290,7 +291,7 @@
<cr-link-row id="paymentManagerButton" <cr-link-row id="paymentManagerButton"
start-icon="settings20:credit-card" start-icon="settings20:credit-card"
label="$i18n{creditCards}" icon-class="subpage-arrow" label="$i18n{creditCards}" icon-class="subpage-arrow"
on-click="onAutofillTap_"></cr-link-row> on-click="onPaymentsTap_"></cr-link-row>
<cr-link-row id="addressesManagerButton" <cr-link-row id="addressesManagerButton"
start-icon="settings20:location-on" start-icon="settings20:location-on"
label="$i18n{addresses}" icon-class="subpage-arrow" label="$i18n{addresses}" icon-class="subpage-arrow"
...@@ -389,6 +390,14 @@ ...@@ -389,6 +390,14 @@
</settings-autofill-section> </settings-autofill-section>
</settings-subpage> </settings-subpage>
</template> </template>
<template is="dom-if" route-path="/payments">
<settings-subpage
associated-control="[[$$('#paymentManagerButton')]]"
page-title="$i18n{creditCards}">
<settings-payments-section id="paymentsSection" prefs="{{prefs}}">
</settings-payments-section>
</settings-subpage>
</template>
</template> </template>
<if expr="chromeos"> <if expr="chromeos">
......
...@@ -147,7 +147,10 @@ Polymer({ ...@@ -147,7 +147,10 @@ Polymer({
settings.routes.MANAGE_PASSWORDS.path, '#passwordManagerButton'); settings.routes.MANAGE_PASSWORDS.path, '#passwordManagerButton');
} }
if (settings.routes.AUTOFILL) { if (settings.routes.AUTOFILL) {
map.set(settings.routes.AUTOFILL.path, '#paymentManagerButton'); map.set(settings.routes.AUTOFILL.path, '#addressesManagerButton');
}
if (settings.routes.PAYMENTS) {
map.set(settings.routes.PAYMENTS.path, '#paymentManagerButton');
} }
// <if expr="not chromeos"> // <if expr="not chromeos">
if (settings.routes.MANAGE_PROFILE) { if (settings.routes.MANAGE_PROFILE) {
...@@ -339,7 +342,7 @@ Polymer({ ...@@ -339,7 +342,7 @@ Polymer({
}, },
/** /**
* Shows the manage autofill sub page. * Shows the manage autofill addresses sub page.
* @param {!Event} event * @param {!Event} event
* @private * @private
*/ */
...@@ -347,6 +350,15 @@ Polymer({ ...@@ -347,6 +350,15 @@ Polymer({
settings.navigateTo(settings.routes.AUTOFILL); settings.navigateTo(settings.routes.AUTOFILL);
}, },
/**
* Shows the manage payment information sub page.
* @param {!Event} event
* @private
*/
onPaymentsTap_: function(event) {
settings.navigateTo(settings.routes.PAYMENTS);
},
/** @private */ /** @private */
onDisconnectClosed_: function() { onDisconnectClosed_: function() {
this.showDisconnectDialog_ = false; this.showDisconnectDialog_ = false;
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
* NETWORK_DETAIL: (undefined|!settings.Route), * NETWORK_DETAIL: (undefined|!settings.Route),
* ON_STARTUP: (undefined|!settings.Route), * ON_STARTUP: (undefined|!settings.Route),
* PASSWORDS: (undefined|!settings.Route), * PASSWORDS: (undefined|!settings.Route),
* PAYMENTS: (undefined|!settings.Route),
* PEOPLE: (undefined|!settings.Route), * PEOPLE: (undefined|!settings.Route),
* POINTERS: (undefined|!settings.Route), * POINTERS: (undefined|!settings.Route),
* POWER: (undefined|!settings.Route), * POWER: (undefined|!settings.Route),
...@@ -275,6 +276,7 @@ cr.define('settings', function() { ...@@ -275,6 +276,7 @@ cr.define('settings', function() {
if (autofillHomeEnabled) { if (autofillHomeEnabled) {
r.AUTOFILL = r.PEOPLE.createChild('/autofill'); r.AUTOFILL = r.PEOPLE.createChild('/autofill');
r.MANAGE_PASSWORDS = r.PEOPLE.createChild('/passwords'); r.MANAGE_PASSWORDS = r.PEOPLE.createChild('/passwords');
r.PAYMENTS = r.PEOPLE.createChild('/payments');
} }
// <if expr="not chromeos"> // <if expr="not chromeos">
r.MANAGE_PROFILE = r.PEOPLE.createChild('/manageProfile'); r.MANAGE_PROFILE = r.PEOPLE.createChild('/manageProfile');
...@@ -375,6 +377,7 @@ cr.define('settings', function() { ...@@ -375,6 +377,7 @@ cr.define('settings', function() {
r.ADVANCED.createSection('/passwordsAndForms', 'passwordsAndForms'); r.ADVANCED.createSection('/passwordsAndForms', 'passwordsAndForms');
r.AUTOFILL = r.PASSWORDS.createChild('/autofill'); r.AUTOFILL = r.PASSWORDS.createChild('/autofill');
r.MANAGE_PASSWORDS = r.PASSWORDS.createChild('/passwords'); r.MANAGE_PASSWORDS = r.PASSWORDS.createChild('/passwords');
r.PAYMENTS = r.PASSWORDS.createChild('/payments');
} }
r.LANGUAGES = r.ADVANCED.createSection('/languages', 'languages'); r.LANGUAGES = r.ADVANCED.createSection('/languages', 'languages');
......
...@@ -760,6 +760,12 @@ ...@@ -760,6 +760,12 @@
<structure name="IDR_SETTINGS_PASSWORDS_EXPORT_DIALOG_JS" <structure name="IDR_SETTINGS_PASSWORDS_EXPORT_DIALOG_JS"
file="passwords_and_forms_page/passwords_export_dialog.js" file="passwords_and_forms_page/passwords_export_dialog.js"
type="chrome_html" /> type="chrome_html" />
<structure name="IDR_SETTINGS_PAYMENTS_SECTION_HTML"
file="passwords_and_forms_page/payments_section.html"
type="chrome_html" />
<structure name="IDR_SETTINGS_PAYMENTS_SECTION_JS"
file="passwords_and_forms_page/payments_section.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_PEOPLE_PAGE_HTML" <structure name="IDR_SETTINGS_PEOPLE_PAGE_HTML"
file="people_page/people_page.html" file="people_page/people_page.html"
type="chrome_html" type="chrome_html"
......
...@@ -1395,6 +1395,7 @@ void AddPasswordsAndFormsStrings(content::WebUIDataSource* html_source) { ...@@ -1395,6 +1395,7 @@ void AddPasswordsAndFormsStrings(content::WebUIDataSource* html_source) {
{"removeAddress", IDS_SETTINGS_ADDRESS_REMOVE}, {"removeAddress", IDS_SETTINGS_ADDRESS_REMOVE},
{"removeCreditCard", IDS_SETTINGS_CREDIT_CARD_REMOVE}, {"removeCreditCard", IDS_SETTINGS_CREDIT_CARD_REMOVE},
{"clearCreditCard", IDS_SETTINGS_CREDIT_CARD_CLEAR}, {"clearCreditCard", IDS_SETTINGS_CREDIT_CARD_CLEAR},
{"creditCardsDetail", IDS_SETTINGS_AUTOFILL_CREDIT_CARD_DETAIL},
{"creditCardType", IDS_SETTINGS_AUTOFILL_CREDIT_CARD_TYPE_COLUMN_LABEL}, {"creditCardType", IDS_SETTINGS_AUTOFILL_CREDIT_CARD_TYPE_COLUMN_LABEL},
{"creditCardExpiration", IDS_SETTINGS_CREDIT_CARD_EXPIRATION_DATE}, {"creditCardExpiration", IDS_SETTINGS_CREDIT_CARD_EXPIRATION_DATE},
{"creditCardName", IDS_SETTINGS_NAME_ON_CREDIT_CARD}, {"creditCardName", IDS_SETTINGS_NAME_ON_CREDIT_CARD},
......
...@@ -90,7 +90,6 @@ js2gtest("browser_tests_js_webui") { ...@@ -90,7 +90,6 @@ js2gtest("browser_tests_js_webui") {
"settings/help_page_browsertest.js", "settings/help_page_browsertest.js",
"settings/passwords_and_autofill_fake_data.js", "settings/passwords_and_autofill_fake_data.js",
"settings/passwords_and_forms_browsertest.js", "settings/passwords_and_forms_browsertest.js",
"settings/settings_autofill_section_browsertest.js",
"settings/settings_idle_load_browsertest.js", "settings/settings_idle_load_browsertest.js",
"settings/settings_page_browsertest.js", "settings/settings_page_browsertest.js",
"settings/settings_passwords_section_browsertest.js", "settings/settings_passwords_section_browsertest.js",
......
...@@ -224,6 +224,60 @@ TEST_F('CrSettingsAboutPageTest', 'AboutPage_OfficialBuild', function() { ...@@ -224,6 +224,60 @@ TEST_F('CrSettingsAboutPageTest', 'AboutPage_OfficialBuild', function() {
}); });
GEN('#endif'); GEN('#endif');
/**
* Test fixture for
* chrome/browser/resources/settings/passwords_and_forms/autofill_section.html.
* @constructor
* @extends {CrSettingsBrowserTest}
*/
function CrSettingsAutofillSectionTest() {}
CrSettingsAutofillSectionTest.prototype = {
__proto__: CrSettingsBrowserTest.prototype,
/** @override */
browsePreload:
'chrome://settings/passwords_and_forms_page/autofill_section.html',
/** @override */
extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
'passwords_and_autofill_fake_data.js',
'test_util.js',
'autofill_section_test.js'
]),
};
TEST_F('CrSettingsAutofillSectionTest', 'All', function() {
mocha.run();
});
/**
* Test fixture for
* chrome/browser/resources/settings/passwords_and_forms/payments_section.html.
* @constructor
* @extends {CrSettingsBrowserTest}
*/
function CrSettingsPaymentsSectionTest() {}
CrSettingsPaymentsSectionTest.prototype = {
__proto__: CrSettingsBrowserTest.prototype,
/** @override */
browsePreload:
'chrome://settings/passwords_and_forms_page/payments_section.html',
/** @override */
extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
'passwords_and_autofill_fake_data.js',
'test_util.js',
'payments_section_test.js'
]),
};
TEST_F('CrSettingsPaymentsSectionTest', 'All', function() {
mocha.run();
});
GEN('#if defined(OS_CHROMEOS)'); GEN('#if defined(OS_CHROMEOS)');
/** /**
......
...@@ -262,17 +262,12 @@ TestPasswordManager.prototype = { ...@@ -262,17 +262,12 @@ TestPasswordManager.prototype = {
}, },
}; };
/** @constructor */ /** Helper class to track AutofillManager expectations. */
function AutofillManagerExpectations() { class AutofillManagerExpectations {
this.requested = { constructor() {
addresses: 0, this.requestedAddresses = 0;
creditCards: 0, this.listeningAddresses = 0;
}; }
this.listening = {
addresses: 0,
creditCards: 0,
};
} }
/** /**
...@@ -286,62 +281,95 @@ function TestAutofillManager() { ...@@ -286,62 +281,95 @@ function TestAutofillManager() {
// Set these to have non-empty data. // Set these to have non-empty data.
this.data = { this.data = {
addresses: [], addresses: [],
creditCards: [],
}; };
// Holds the last callbacks so they can be called when needed. // Holds the last callbacks so they can be called when needed.
this.lastCallback = { this.lastCallback = {
addAddressListChangedListener: null, addAddressListChangedListener: null,
addCreditCardListChangedListener: null,
}; };
} }
TestAutofillManager.prototype = { TestAutofillManager.prototype = {
/** @override */ /** @override */
addAddressListChangedListener: function(listener) { addAddressListChangedListener: function(listener) {
this.actual_.listening.addresses++; this.actual_.listeningAddresses++;
this.lastCallback.addAddressListChangedListener = listener; this.lastCallback.addAddressListChangedListener = listener;
}, },
/** @override */ /** @override */
removeAddressListChangedListener: function(listener) { removeAddressListChangedListener: function(listener) {
this.actual_.listening.addresses--; this.actual_.listeningAddresses--;
}, },
/** @override */ /** @override */
getAddressList: function(callback) { getAddressList: function(callback) {
this.actual_.requested.addresses++; this.actual_.requestedAddresses++;
callback(this.data.addresses); callback(this.data.addresses);
}, },
/**
* Verifies expectations.
* @param {!AutofillManagerExpectations} expected
*/
assertExpectations: function(expected) {
const actual = this.actual_;
assertEquals(expected.requestedAddresses, actual.requestedAddresses);
assertEquals(expected.listeningAddresses, actual.listeningAddresses);
},
};
/** Helper class to track PaymentsManager expectations. */
class PaymentsManagerExpectations {
constructor() {
this.requestedCreditCards = 0;
this.listeningCreditCards = 0;
}
}
/**
* Test implementation
* @implements {PaymentsManager}
* @constructor
*/
function TestPaymentsManager() {
this.actual_ = new PaymentsManagerExpectations();
// Set these to have non-empty data.
this.data = {
creditCards: [],
};
// Holds the last callbacks so they can be called when needed.
this.lastCallback = {
addCreditCardListChangedListener: null,
};
}
TestPaymentsManager.prototype = {
/** @override */ /** @override */
addCreditCardListChangedListener: function(listener) { addCreditCardListChangedListener: function(listener) {
this.actual_.listening.creditCards++; this.actual_.listeningCreditCards++;
this.lastCallback.addCreditCardListChangedListener = listener; this.lastCallback.addCreditCardListChangedListener = listener;
}, },
/** @override */ /** @override */
removeCreditCardListChangedListener: function(listener) { removeCreditCardListChangedListener: function(listener) {
this.actual_.listening.creditCards--; this.actual_.listeningCreditCards--;
}, },
/** @override */ /** @override */
getCreditCardList: function(callback) { getCreditCardList: function(callback) {
this.actual_.requested.creditCards++; this.actual_.requestedCreditCards++;
callback(this.data.creditCards); callback(this.data.creditCards);
}, },
/** /**
* Verifies expectations. * Verifies expectations.
* @param {!AutofillManagerExpectations} expected * @param {!PaymentsManagerExpectations} expected
*/ */
assertExpectations: function(expected) { assertExpectations: function(expected) {
const actual = this.actual_; const actual = this.actual_;
assertEquals(expected.requestedCreditCards, actual.requestedCreditCards);
assertEquals(expected.requested.addresses, actual.requested.addresses); assertEquals(expected.listeningCreditCards, actual.listeningCreditCards);
assertEquals(expected.requested.creditCards, actual.requested.creditCards);
assertEquals(expected.listening.addresses, actual.listening.addresses);
assertEquals(expected.listening.creditCards, actual.listening.creditCards);
}, },
}; };
...@@ -51,6 +51,7 @@ PasswordsAndFormsBrowserTest.prototype = { ...@@ -51,6 +51,7 @@ PasswordsAndFormsBrowserTest.prototype = {
TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() { TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() {
let passwordManager; let passwordManager;
let autofillManager; let autofillManager;
let paymentsManager;
/** /**
* Creates a new passwords and forms element. * Creates a new passwords and forms element.
...@@ -65,6 +66,7 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() { ...@@ -65,6 +66,7 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() {
const domIfTag = Polymer.DomIf ? 'dom-if' : 'template'; const domIfTag = Polymer.DomIf ? 'dom-if' : 'template';
element.$$(`${domIfTag}[route-path="/passwords"]`).if = true; element.$$(`${domIfTag}[route-path="/passwords"]`).if = true;
element.$$(`${domIfTag}[route-path="/autofill"]`).if = true; element.$$(`${domIfTag}[route-path="/autofill"]`).if = true;
element.$$(`${domIfTag}[route-path="/payments"]`).if = true;
Polymer.dom.flush(); Polymer.dom.flush();
return element; return element;
} }
...@@ -143,10 +145,20 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() { ...@@ -143,10 +145,20 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() {
*/ */
function baseAutofillExpectations() { function baseAutofillExpectations() {
const expected = new AutofillManagerExpectations(); const expected = new AutofillManagerExpectations();
expected.requested.addresses = 1; expected.requestedAddresses = 1;
expected.requested.creditCards = 1; expected.listeningAddresses = 1;
expected.listening.addresses = 1; return expected;
expected.listening.creditCards = 1; }
/**
* Creates PaymentsManagerExpectations with the values expected after first
* creating the element.
* @return {!PaymentsManagerExpectations}
*/
function basePaymentsExpectations() {
const expected = new PaymentsManagerExpectations();
expected.requestedCreditCards = 1;
expected.listeningCreditCards = 1;
return expected; return expected;
} }
...@@ -160,6 +172,10 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() { ...@@ -160,6 +172,10 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() {
// Override the AutofillManagerImpl for testing. // Override the AutofillManagerImpl for testing.
autofillManager = new TestAutofillManager(); autofillManager = new TestAutofillManager();
AutofillManagerImpl.instance_ = autofillManager; AutofillManagerImpl.instance_ = autofillManager;
// Override the PaymentsManagerImpl for testing.
paymentsManager = new TestPaymentsManager();
PaymentsManagerImpl.instance_ = paymentsManager;
}); });
suite('PasswordsAndForms', function() { suite('PasswordsAndForms', function() {
...@@ -173,6 +189,9 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() { ...@@ -173,6 +189,9 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() {
const autofillExpectations = baseAutofillExpectations(); const autofillExpectations = baseAutofillExpectations();
autofillManager.assertExpectations(autofillExpectations); autofillManager.assertExpectations(autofillExpectations);
const paymentsExpectations = basePaymentsExpectations();
paymentsManager.assertExpectations(paymentsExpectations);
element.remove(); element.remove();
Polymer.dom.flush(); Polymer.dom.flush();
...@@ -180,10 +199,12 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() { ...@@ -180,10 +199,12 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() {
passwordsExpectations.listening.exceptions = 0; passwordsExpectations.listening.exceptions = 0;
passwordManager.assertExpectations(passwordsExpectations); passwordManager.assertExpectations(passwordsExpectations);
autofillExpectations.listening.addresses = 0; autofillExpectations.listeningAddresses = 0;
autofillExpectations.listening.creditCards = 0;
autofillManager.assertExpectations(autofillExpectations); autofillManager.assertExpectations(autofillExpectations);
paymentsExpectations.listeningCreditCards = 0;
paymentsManager.assertExpectations(paymentsExpectations);
destroyPrefs(prefs); destroyPrefs(prefs);
}); });
}); });
...@@ -207,6 +228,7 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() { ...@@ -207,6 +228,7 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() {
// have additional calls to the manager after the base expectations. // have additional calls to the manager after the base expectations.
passwordManager.assertExpectations(basePasswordExpectations()); passwordManager.assertExpectations(basePasswordExpectations());
autofillManager.assertExpectations(baseAutofillExpectations()); autofillManager.assertExpectations(baseAutofillExpectations());
paymentsManager.assertExpectations(basePaymentsExpectations());
destroyPrefs(prefs); destroyPrefs(prefs);
}); });
...@@ -227,6 +249,7 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() { ...@@ -227,6 +249,7 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() {
// have additional calls to the manager after the base expectations. // have additional calls to the manager after the base expectations.
passwordManager.assertExpectations(basePasswordExpectations()); passwordManager.assertExpectations(basePasswordExpectations());
autofillManager.assertExpectations(baseAutofillExpectations()); autofillManager.assertExpectations(baseAutofillExpectations());
paymentsManager.assertExpectations(basePaymentsExpectations());
destroyPrefs(prefs); destroyPrefs(prefs);
}); });
...@@ -247,6 +270,7 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() { ...@@ -247,6 +270,7 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() {
// have additional calls to the manager after the base expectations. // have additional calls to the manager after the base expectations.
passwordManager.assertExpectations(basePasswordExpectations()); passwordManager.assertExpectations(basePasswordExpectations());
autofillManager.assertExpectations(baseAutofillExpectations()); autofillManager.assertExpectations(baseAutofillExpectations());
paymentsManager.assertExpectations(basePaymentsExpectations());
destroyPrefs(prefs); destroyPrefs(prefs);
}); });
...@@ -258,15 +282,16 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() { ...@@ -258,15 +282,16 @@ TEST_F('PasswordsAndFormsBrowserTest', 'uiTests', function() {
const list = const list =
[FakeDataMaker.creditCardEntry(), FakeDataMaker.creditCardEntry()]; [FakeDataMaker.creditCardEntry(), FakeDataMaker.creditCardEntry()];
autofillManager.lastCallback.addCreditCardListChangedListener(list); paymentsManager.lastCallback.addCreditCardListChangedListener(list);
Polymer.dom.flush(); Polymer.dom.flush();
assertEquals(list, element.$$('#autofillSection').creditCards); assertEquals(list, element.$$('#paymentSection').creditCards);
// The callback is coming from the manager, so the element shouldn't // The callback is coming from the manager, so the element shouldn't
// have additional calls to the manager after the base expectations. // have additional calls to the manager after the base expectations.
passwordManager.assertExpectations(basePasswordExpectations()); passwordManager.assertExpectations(basePasswordExpectations());
autofillManager.assertExpectations(baseAutofillExpectations()); autofillManager.assertExpectations(baseAutofillExpectations());
paymentsManager.assertExpectations(basePaymentsExpectations());
destroyPrefs(prefs); destroyPrefs(prefs);
}); });
......
This diff is collapsed.
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