| // 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); |
| }, |
| }); |
| })(); |