blob: 399e3f806e43dcdf70e19dac891272eec8a1c678 [file] [log] [blame]
// 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 'settings-autofill-section' is the section containing saved
* addresses for use in autofill and payments APIs.
*/
import 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js';
import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
import 'chrome://resources/cr_elements/shared_style_css.m.js';
import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js';
import '../settings_shared.css.js';
import '../controls/extension_controlled_indicator.js';
import '../controls/settings_toggle_button.js';
import '../prefs/prefs.js';
import './address_edit_dialog.js';
import './address_remove_confirmation_dialog.js';
import './passwords_shared.css.js';
import '../i18n_setup.js';
import {I18nMixin} from '//resources/js/i18n_mixin.js';
import {CrActionMenuElement} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js';
import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
import {assert} from 'chrome://resources/js/assert_ts.js';
import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js';
import {DomRepeatEvent, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js';
import {AutofillManagerImpl, AutofillManagerProxy, PersonalDataChangedListener} from './autofill_manager_proxy.js';
import {getTemplate} from './autofill_section.html.js';
declare global {
interface HTMLElementEventMap {
'save-address': CustomEvent<chrome.autofillPrivate.AddressEntry>;
}
}
export interface SettingsAutofillSectionElement {
$: {
autofillProfileToggle: SettingsToggleButtonElement,
addressSharedMenu: CrActionMenuElement,
addAddress: CrButtonElement,
addressList: HTMLElement,
menuRemoveAddress: HTMLElement,
noAddressesLabel: HTMLElement,
};
}
const SettingsAutofillSectionElementBase = I18nMixin(PolymerElement);
export class SettingsAutofillSectionElement extends
SettingsAutofillSectionElementBase {
static get is() {
return 'settings-autofill-section';
}
static get template() {
return getTemplate();
}
static get properties() {
return {
/** An array of saved addresses. */
addresses: Array,
/** The model for any address related action menus or dialogs. */
activeAddress: Object,
showAddressDialog_: Boolean,
showAddressRemoveConfirmationDialog_: Boolean,
};
}
prefs: {[key: string]: any};
addresses: chrome.autofillPrivate.AddressEntry[];
activeAddress: chrome.autofillPrivate.AddressEntry|null;
private showAddressDialog_: boolean;
private showAddressRemoveConfirmationDialog_: boolean;
private activeDialogAnchor_: HTMLElement|null;
private autofillManager_: AutofillManagerProxy =
AutofillManagerImpl.getInstance();
private setPersonalDataListener_: PersonalDataChangedListener|null = null;
constructor() {
super();
/**
* The element to return focus to, when the currently active dialog is
* closed.
*/
this.activeDialogAnchor_ = null;
}
override ready() {
super.ready();
this.addEventListener('save-address', this.saveAddress_);
}
override connectedCallback() {
super.connectedCallback();
// Create listener functions.
const setAddressesListener =
(addressList: chrome.autofillPrivate.AddressEntry[]) => {
this.addresses = addressList;
};
const setPersonalDataListener: PersonalDataChangedListener =
(addressList, _cardList) => {
this.addresses = addressList;
};
// Remember the bound reference in order to detach.
this.setPersonalDataListener_ = setPersonalDataListener;
// Request initial data.
this.autofillManager_.getAddressList(setAddressesListener);
// Listen for changes.
this.autofillManager_.setPersonalDataManagerListener(
setPersonalDataListener);
// Record that the user opened the address settings.
chrome.metricsPrivate.recordUserAction('AutofillAddressesViewed');
}
override disconnectedCallback() {
super.disconnectedCallback();
this.autofillManager_.removePersonalDataManagerListener(
this.setPersonalDataListener_!);
this.setPersonalDataListener_ = null;
}
/**
* Open the address action menu.
*/
private onAddressMenuTap_(
e: DomRepeatEvent<chrome.autofillPrivate.AddressEntry>) {
const item = e.model.item;
// Copy item so dialog won't update model on cancel.
this.activeAddress = Object.assign({}, item);
const dotsButton = e.target as HTMLElement;
this.$.addressSharedMenu.showAt(dotsButton);
this.activeDialogAnchor_ = dotsButton;
}
/**
* Handles tapping on the "Add address" button.
*/
private onAddAddressTap_(e: Event) {
e.preventDefault();
this.activeAddress = {};
this.showAddressDialog_ = true;
this.activeDialogAnchor_ = this.$.addAddress;
}
private onAddressDialogClose_() {
this.showAddressDialog_ = false;
assert(this.activeDialogAnchor_);
focusWithoutInk(this.activeDialogAnchor_);
this.activeDialogAnchor_ = null;
}
/**
* Handles tapping on the "Edit" address button.
*/
private onMenuEditAddressTap_(e: Event) {
e.preventDefault();
this.showAddressDialog_ = true;
this.$.addressSharedMenu.close();
}
private onAddressRemoveConfirmationDialogClose_() {
// Check if the dialog was confirmed before closing it.
if (this.shadowRoot!
.querySelector('settings-address-remove-confirmation-dialog')!
.wasConfirmed()) {
this.autofillManager_.removeAddress(this.activeAddress!.guid as string);
}
this.showAddressRemoveConfirmationDialog_ = false;
assert(this.activeDialogAnchor_);
focusWithoutInk(this.activeDialogAnchor_);
this.activeDialogAnchor_ = null;
}
/**
* Handles tapping on the "Remove" address button.
*/
private onMenuRemoveAddressTap_() {
this.showAddressRemoveConfirmationDialog_ = true;
this.$.addressSharedMenu.close();
}
/**
* @return Whether the list exists and has items.
*/
private hasSome_(list: Object[]): boolean {
return !!(list && list.length);
}
/**
* Listens for the save-address event, and calls the private API.
*/
private saveAddress_(event:
CustomEvent<chrome.autofillPrivate.AddressEntry>) {
this.autofillManager_.saveAddress(event.detail);
}
/**
* @returns the title for the More Actions button corresponding to the address
* which is described by `label` and `sublabel`.
*/
private moreActionsTitle_(label: string, sublabel: string) {
return this.i18n(
'moreActionsForAddress', label + (sublabel ? sublabel : ''));
}
}
declare global {
interface HTMLElementTagNameMap {
'settings-autofill-section': SettingsAutofillSectionElement;
}
}
customElements.define(
SettingsAutofillSectionElement.is, SettingsAutofillSectionElement);