// Copyright 2016 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 'password-edit-dialog' is the dialog that allows showing a * saved password. */ (function() { 'use strict'; Polymer({ is: 'settings-address-edit-dialog', behaviors: [ I18nBehavior, ], properties: { /** @type {chrome.autofillPrivate.AddressEntry} */ address: Object, /** @private */ title_: String, /** @private {!Array} */ countries_: Array, /** * Updates the address wrapper. * @private {string|undefined} */ countryCode_: { type: String, observer: 'onUpdateCountryCode_', }, /** @private {!Array>} */ addressWrapper_: Object, /** @private */ phoneNumber_: String, /** @private */ email_: String, /** @private */ canSave_: Boolean, }, /** @override */ attached: function() { this.countryInfo = settings.address.CountryDetailManagerImpl.getInstance(); this.countryInfo.getCountryList().then(countryList => { this.countries_ = countryList; this.title_ = this.i18n(this.address.guid ? 'editAddressTitle' : 'addAddressTitle'); // |phoneNumbers| and |emailAddresses| are a single item array. // See crbug.com/497934 for details. this.phoneNumber_ = this.address.phoneNumbers ? this.address.phoneNumbers[0] : ''; this.email_ = this.address.emailAddresses ? this.address.emailAddresses[0] : ''; this.async(() => { if (this.countryCode_ == this.address.countryCode) { this.updateAddressWrapper_(); } else { this.countryCode_ = this.address.countryCode; } }); }); // Open is called on the dialog after the address wrapper has been updated. }, /** * Returns a class to denote how long this entry is. * @param {settings.address.AddressComponentUI} setting * @return {string} */ long_: function(setting) { return setting.component.isLongField ? 'long' : ''; }, /** * Updates the wrapper that represents this address in the country's format. * @private */ updateAddressWrapper_: function() { // Default to the last country used if no country code is provided. const countryCode = this.countryCode_ || this.countries_[0].countryCode; this.countryInfo.getAddressFormat(countryCode).then(format => { this.addressWrapper_ = format.components.map( component => component.row.map( c => new settings.address.AddressComponentUI(this.address, c))); // Flush dom before resize and savability updates. Polymer.dom.flush(); this.updateCanSave_(); this.fire('on-update-address-wrapper'); // For easier testing. const dialog = /** @type {HTMLDialogElement} */ (this.$.dialog); if (!dialog.open) { dialog.showModal(); } }); }, updateCanSave_: function() { const inputs = this.$.dialog.querySelectorAll('.address-column, select'); for (let i = 0; i < inputs.length; ++i) { if (inputs[i].value) { this.canSave_ = true; this.fire('on-update-can-save'); // For easier testing. return; } } this.canSave_ = false; this.fire('on-update-can-save'); // For easier testing. }, /** * @param {!chrome.autofillPrivate.CountryEntry} country * @return {string} * @private */ getCode_: function(country) { return country.countryCode || 'SPACER'; }, /** * @param {!chrome.autofillPrivate.CountryEntry} country * @return {string} * @private */ getName_: function(country) { return country.name || '------'; }, /** * @param {!chrome.autofillPrivate.CountryEntry} country * @return {boolean} * @private */ isDivision_: function(country) { return !country.countryCode; }, /** @private */ onCancelTap_: function() { this.$.dialog.cancel(); }, /** * Handler for tapping the save button. * @private */ onSaveButtonTap_: function() { // The Enter key can call this function even if the button is disabled. if (!this.canSave_) { return; } // Set a default country if none is set. if (!this.address.countryCode) { this.address.countryCode = this.countries_[0].countryCode; } this.address.phoneNumbers = this.phoneNumber_ ? [this.phoneNumber_] : []; this.address.emailAddresses = this.email_ ? [this.email_] : []; this.fire('save-address', this.address); this.$.dialog.close(); }, /** * Syncs the country code back to the address and rebuilds the address wrapper * for the new location. * @param {string|undefined} countryCode * @private */ onUpdateCountryCode_: function(countryCode) { this.address.countryCode = countryCode; this.updateAddressWrapper_(); }, /** @private */ onCountryChange_: function() { const countrySelect = /** @type {!HTMLSelectElement} */ (this.$$('select')); this.countryCode_ = countrySelect.value; }, }); })(); cr.define('settings.address', function() { /** * Creates a wrapper against a single data member for an address. */ class AddressComponentUI { /** * @param {!chrome.autofillPrivate.AddressEntry} address * @param {!chrome.autofillPrivate.AddressComponent} component */ constructor(address, component) { Object.defineProperty(this, 'value', { get: function() { return this.getValue_(); }, set: function(newValue) { this.setValue_(newValue); }, }); this.address_ = address; this.component = component; this.isTextArea = component.field == chrome.autofillPrivate.AddressField.ADDRESS_LINES; } /** * Gets the value from the address that's associated with this component. * @return {string|undefined} * @private */ getValue_() { const address = this.address_; switch (this.component.field) { case chrome.autofillPrivate.AddressField.FULL_NAME: // |fullNames| is a single item array. See crbug.com/497934 for // details. return address.fullNames ? address.fullNames[0] : undefined; case chrome.autofillPrivate.AddressField.COMPANY_NAME: return address.companyName; case chrome.autofillPrivate.AddressField.ADDRESS_LINES: return address.addressLines; case chrome.autofillPrivate.AddressField.ADDRESS_LEVEL_1: return address.addressLevel1; case chrome.autofillPrivate.AddressField.ADDRESS_LEVEL_2: return address.addressLevel2; case chrome.autofillPrivate.AddressField.ADDRESS_LEVEL_3: return address.addressLevel3; case chrome.autofillPrivate.AddressField.POSTAL_CODE: return address.postalCode; case chrome.autofillPrivate.AddressField.SORTING_CODE: return address.sortingCode; case chrome.autofillPrivate.AddressField.COUNTRY_CODE: return address.countryCode; default: assertNotReached(); } } /** * Sets the value in the address that's associated with this component. * @param {string} value * @private */ setValue_(value) { const address = this.address_; switch (this.component.field) { case chrome.autofillPrivate.AddressField.FULL_NAME: address.fullNames = [value]; break; case chrome.autofillPrivate.AddressField.COMPANY_NAME: address.companyName = value; break; case chrome.autofillPrivate.AddressField.ADDRESS_LINES: address.addressLines = value; break; case chrome.autofillPrivate.AddressField.ADDRESS_LEVEL_1: address.addressLevel1 = value; break; case chrome.autofillPrivate.AddressField.ADDRESS_LEVEL_2: address.addressLevel2 = value; break; case chrome.autofillPrivate.AddressField.ADDRESS_LEVEL_3: address.addressLevel3 = value; break; case chrome.autofillPrivate.AddressField.POSTAL_CODE: address.postalCode = value; break; case chrome.autofillPrivate.AddressField.SORTING_CODE: address.sortingCode = value; break; case chrome.autofillPrivate.AddressField.COUNTRY_CODE: address.countryCode = value; break; default: assertNotReached(); } } } /** @interface */ class CountryDetailManager { /** * Gets the list of available countries. * The default country will be first, followed by a separator, followed by * an alphabetized list of countries available. * @return {!Promise>} */ getCountryList() {} /** * Gets the address format for a given country code. * @param {string} countryCode * @return {!Promise} */ getAddressFormat(countryCode) {} } /** * Default implementation. Override for testing. * @implements {settings.address.CountryDetailManager} */ class CountryDetailManagerImpl { /** @override */ getCountryList() { return new Promise(function(callback) { chrome.autofillPrivate.getCountryList(callback); }); } /** @override */ getAddressFormat(countryCode) { return new Promise(function(callback) { chrome.autofillPrivate.getAddressComponents(countryCode, callback); }); } } cr.addSingletonGetter(CountryDetailManagerImpl); return { AddressComponentUI: AddressComponentUI, CountryDetailManager: CountryDetailManager, CountryDetailManagerImpl: CountryDetailManagerImpl, }; });