// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview 'settings-clear-browsing-data-dialog' allows the user to
* delete browsing data that has been cached by Chromium.
*/
import 'chrome://resources/cr_elements/cr_button/cr_button.js';
import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
import 'chrome://resources/cr_elements/cr_tabs/cr_tabs.js';
import 'chrome://resources/cr_elements/cr_shared_vars.css.js';
import 'chrome://resources/cr_elements/cr_page_selector/cr_page_selector.js';
import 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js';
import './history_deletion_dialog.js';
import './passwords_deletion_dialog.js';
import '../controls/settings_checkbox.js';
import '../icons.html.js';
import '../settings_shared.css.js';
// <if expr="not is_chromeos">
import '../people_page/sync_account_control.js';
// </if>
import type {SyncBrowserProxy, SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
import {SignedInState, StatusAction, SyncBrowserProxyImpl} from '/shared/settings/people_page/sync_browser_proxy.js';
import {PrefsMixin} from '/shared/settings/prefs/prefs_mixin.js';
import {getInstance as getAnnouncerInstance} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
import type {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js';
import type {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
import type {CrPageSelectorElement} from 'chrome://resources/cr_elements/cr_page_selector/cr_page_selector.js';
import type {CrTabsElement} from 'chrome://resources/cr_elements/cr_tabs/cr_tabs.js';
import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
import {assert, assertNotReached} from 'chrome://resources/js/assert.js';
import {FocusOutlineManager} from 'chrome://resources/js/focus_outline_manager.js';
import {sanitizeInnerHtml} from 'chrome://resources/js/parse_html_subset.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import type {SettingsCheckboxElement} from '../controls/settings_checkbox.js';
import type {DropdownMenuOptionList, SettingsDropdownMenuElement} from '../controls/settings_dropdown_menu.js';
import {loadTimeData} from '../i18n_setup.js';
import {routes} from '../route.js';
import type {Route} from '../router.js';
import {RouteObserverMixin, Router} from '../router.js';
import type {ClearBrowsingDataBrowserProxy, UpdateSyncStateEvent} from './clear_browsing_data_browser_proxy.js';
import {ClearBrowsingDataBrowserProxyImpl, TimePeriod, TimePeriodExperiment} from './clear_browsing_data_browser_proxy.js';
import {getTemplate} from './clear_browsing_data_dialog.html.js';
/**
* @param dialog the dialog to close
* @param isLast whether this is the last CBD-related dialog
*/
function closeDialog(dialog: CrDialogElement, isLast: boolean) {
// If this is not the last dialog, then stop the 'close' event from
// propagating so that other (following) dialogs don't get closed as well.
if (!isLast) {
dialog.addEventListener('close', e => {
e.stopPropagation();
}, {once: true});
}
dialog.close();
}
export interface SettingsClearBrowsingDataDialogElement {
$: {
clearBrowsingDataConfirm: HTMLElement,
cookiesCheckbox: SettingsCheckboxElement,
cookiesCheckboxBasic: SettingsCheckboxElement,
clearButton: CrButtonElement,
clearBrowsingDataDialog: CrDialogElement,
pages: CrPageSelectorElement,
tabs: CrTabsElement,
};
}
const SettingsClearBrowsingDataDialogElementBase = RouteObserverMixin(
WebUiListenerMixin(PrefsMixin(I18nMixin(PolymerElement))));
export class SettingsClearBrowsingDataDialogElement extends
SettingsClearBrowsingDataDialogElementBase {
static get is() {
return 'settings-clear-browsing-data-dialog';
}
static get template() {
return getTemplate();
}
static get properties() {
return {
/**
* Preferences state.
*/
prefs: {
type: Object,
notify: true,
},
/**
* The current sync status, supplied by SyncBrowserProxy.
*/
syncStatus: Object,
/**
* Results of browsing data counters, keyed by the suffix of
* the corresponding data type deletion preference, as reported
* by the C++ side.
*/
counters_: {
type: Object,
// Will be filled as results are reported.
value() {
return {};
},
},
/**
* List of options for the dropdown menu.
*/
clearFromOptions_: {
readOnly: true,
type: Array,
value: [
{
value: TimePeriod.LAST_HOUR,
name: loadTimeData.getString('clearPeriodHour'),
},
{
value: TimePeriod.LAST_DAY,
name: loadTimeData.getString('clearPeriod24Hours'),
},
{
value: TimePeriod.LAST_WEEK,
name: loadTimeData.getString('clearPeriod7Days'),
},
{
value: TimePeriod.FOUR_WEEKS,
name: loadTimeData.getString('clearPeriod4Weeks'),
},
{
value: TimePeriod.ALL_TIME,
name: loadTimeData.getString('clearPeriodEverything'),
},
],
},
enableCbdTimeframeRequired_: {
type: Boolean,
value() {
return loadTimeData.getBoolean('enableCbdTimeframeRequired');
},
},
unoDesktopEnabled_: {
type: Boolean,
value() {
return loadTimeData.getBoolean('unoDesktopEnabled');
},
},
/**
* When CBDTimeframeRequired feature/flag is on, this will be the list
* of options for the dropdown menu. V2 additionally contains the "Last 15
* minutes" and the "Select a time range" options with "Select a time
* range" being always hidden in the menuOptions list in which users can
* chose the time range.
*/
clearFromOptionsV2_: {
readOnly: true,
type: Array,
value: [
// The pref is initialized to TimePeriodExperiment.NOT_SELECTED, which
// is shown in the dropdown as the selected option until the user
// selects a different value. The menuList of options should not
// contain the option for TimePeriodExperiment.NOT_SELECTED, as it
// doesn't make sense for users to choose it.
{
value: TimePeriodExperiment.NOT_SELECTED,
name: loadTimeData.getString('clearPeriodNotSelected'),
hidden: true,
},
// The value of 15min is 6 to match the value written in the backend,
// Also, it comes first in the list to keep the list in ascending
// order.
{
value: TimePeriodExperiment.LAST_15_MINUTES,
name: loadTimeData.getString('clearPeriod15Minutes'),
},
{
value: TimePeriodExperiment.LAST_HOUR,
name: loadTimeData.getString('clearPeriodHour'),
},
{
value: TimePeriodExperiment.LAST_DAY,
name: loadTimeData.getString('clearPeriod24Hours'),
},
{
value: TimePeriodExperiment.LAST_WEEK,
name: loadTimeData.getString('clearPeriod7Days'),
},
{
value: TimePeriodExperiment.FOUR_WEEKS,
name: loadTimeData.getString('clearPeriod4Weeks'),
},
{
value: TimePeriodExperiment.ALL_TIME,
name: loadTimeData.getString('clearPeriodEverything'),
},
],
},
clearingInProgress_: {
type: Boolean,
value: false,
},
clearingDataAlertString_: {
type: String,
value: '',
},
clearButtonDisabled_: {
type: Boolean,
value: false,
},
showHistoryDeletionDialog_: {
type: Boolean,
value: false,
},
showPasswordsDeletionDialogLater_: {
type: Boolean,
value: false,
},
showPasswordsDeletionDialog_: {
type: Boolean,
value: false,
},
isSignedIn_: {
type: Boolean,
value: false,
},
isSyncConsented_: {
type: Boolean,
value: false,
},
isSyncingHistory_: {
type: Boolean,
value: false,
},
shouldShowCookieException_: {
type: Boolean,
value: false,
},
// <if expr="not is_chromeos">
isClearPrimaryAccountAllowed_: {
type: Boolean,
value() {
return loadTimeData.getBoolean('isClearPrimaryAccountAllowed');
},
},
isSyncPaused_: {
type: Boolean,
value: false,
computed: 'computeIsSyncPaused_(syncStatus)',
},
hasPassphraseError_: {
type: Boolean,
value: false,
computed: 'computeHasPassphraseError_(syncStatus)',
},
hasOtherSyncError_: {
type: Boolean,
value: false,
computed:
'computeHasOtherError_(syncStatus, isSyncPaused_, hasPassphraseError_)',
},
// </if>
selectedTabIndex_: Number,
tabsNames_: {
type: Array,
value: () =>
[loadTimeData.getString('basicPageTitle'),
loadTimeData.getString('advancedPageTitle'),
],
},
googleSearchHistoryString_: {
type: String,
computed: 'computeGoogleSearchHistoryString_(isNonGoogleDse_)',
},
isNonGoogleDse_: {
type: Boolean,
value: false,
},
nonGoogleSearchHistoryString_: String,
};
}
static get observers() {
return [
`onTimePeriodAdvancedPrefUpdated_(
prefs.browser.clear_data.time_period.value)`,
`onTimePeriodBasicPrefUpdated_(
prefs.browser.clear_data.time_period_basic.value)`,
`onSelectedTabIndexPrefUpdated_(
prefs.browser.last_clear_browsing_data_tab.value)`,
];
}
// TODO(dpapad): make |syncStatus| private.
syncStatus: SyncStatus|undefined;
private counters_: {[k: string]: string};
private clearFromOptions_: DropdownMenuOptionList;
private clearFromOptionsV2_: DropdownMenuOptionList;
private enableCbdTimeframeRequired_: boolean;
private unoDesktopEnabled_: boolean;
private clearingInProgress_: boolean;
private clearingDataAlertString_: string;
private clearButtonDisabled_: boolean;
private showHistoryDeletionDialog_: boolean;
private showPasswordsDeletionDialogLater_: boolean;
private showPasswordsDeletionDialog_: boolean;
private isSignedIn_: boolean;
private isSyncConsented_: boolean;
private isSyncingHistory_: boolean;
private shouldShowCookieException_: boolean;
// <if expr="not is_chromeos">
private isClearPrimaryAccountAllowed_: boolean;
private isSyncPaused_: boolean;
private hasPassphraseError_: boolean;
private hasOtherSyncError_: boolean;
// </if>
private selectedTabIndex_: number;
private tabsNames_: string[];
private googleSearchHistoryString_: TrustedHTML;
private isNonGoogleDse_: boolean;
private nonGoogleSearchHistoryString_: TrustedHTML;
private focusOutlineManager_: FocusOutlineManager;
private browserProxy_: ClearBrowsingDataBrowserProxy =
ClearBrowsingDataBrowserProxyImpl.getInstance();
private syncBrowserProxy_: SyncBrowserProxy =
SyncBrowserProxyImpl.getInstance();
override ready() {
super.ready();
this.syncBrowserProxy_.getSyncStatus().then(
this.handleSyncStatus_.bind(this));
this.addWebUiListener(
'sync-status-changed', this.handleSyncStatus_.bind(this));
this.addWebUiListener(
'update-sync-state', this.updateSyncState_.bind(this));
this.addWebUiListener(
'update-counter-text', this.updateCounterText_.bind(this));
this.addEventListener(
'settings-boolean-control-change', this.updateClearButtonState_);
}
override connectedCallback() {
super.connectedCallback();
this.browserProxy_.initialize().then(() => {
this.$.clearBrowsingDataDialog.showModal();
// AutoFocus is not visible in mouse navigation by default. But in this
// dialog the default focus is on cancel which is not a default button. To
// make this clear to the user we make it visible to the user and remove
// the focus after the next mouse event.
this.focusOutlineManager_ = FocusOutlineManager.forDocument(document);
this.focusOutlineManager_.visible = true;
document.addEventListener('mousedown', () => {
this.focusOutlineManager_.visible = false;
}, {once: true});
});
}
/**
* Handler for when the sync state is pushed from the browser.
*/
private handleSyncStatus_(syncStatus: SyncStatus) {
this.syncStatus = syncStatus;
}
/**
* @return Whether either clearing is in progress or no data type is selected.
*/
private isClearButtonDisabled_(
clearingInProgress: boolean, clearButtonDisabled: boolean): boolean {
return clearingInProgress || clearButtonDisabled;
}
/**
* Disables the Clear Data button if no data type is selected.
*/
private updateClearButtonState_() {
// on-select-item-changed gets called with undefined during a tab change.
// https://github.com/PolymerElements/iron-selector/issues/95
const page = this.$.pages.selectedItem;
if (!page) {
return;
}
this.clearButtonDisabled_ =
this.getSelectedDataTypes_(page as HTMLElement).length === 0;
}
/**
* Record visits to the CBD dialog.
*
* RouteObserverMixin
*/
override currentRouteChanged(currentRoute: Route) {
if (currentRoute === routes.CLEAR_BROWSER_DATA) {
chrome.metricsPrivate.recordUserAction('ClearBrowsingData_DialogCreated');
}
}
/**
* Updates the history description to show the relevant information
* depending on sync and signin state.
*/
private updateSyncState_(event: UpdateSyncStateEvent) {
this.isSignedIn_ = event.signedIn;
this.isSyncConsented_ = event.syncConsented;
this.isSyncingHistory_ = event.syncingHistory;
this.shouldShowCookieException_ = event.shouldShowCookieException;
this.$.clearBrowsingDataDialog.classList.add('fully-rendered');
this.isNonGoogleDse_ = event.isNonGoogleDse;
this.nonGoogleSearchHistoryString_ =
sanitizeInnerHtml(event.nonGoogleSearchHistoryString);
}
/** Choose a label for the history checkbox. */
private browsingCheckboxLabel_(
isSyncingHistory: boolean, historySummary: string,
historySummarySignedInNoLink: string): string {
return isSyncingHistory ? historySummarySignedInNoLink : historySummary;
}
/**
* Choose a label for the cookie checkbox
* @param signedInState SignedInState
* @param shouldShowCookieException boolean whether the exception about not
* being signed out of your Google account should be shown when user is
* sync.
* @param cookiesSummary string explaining that deleting cookies and site data
* will sign the user out of most websites.
* @param clearCookiesSummarySignedIn string explaining that deleting cookies
* and site data will sign the user out of most websites but Google sign in
* will stay.
* @param clearCookiesSummarySyncing string explaining that deleting cookies
* and site data will sign the user out of most websites but Google sign in
* will stay when user is syncing.
* @param clearCookiesSummarySignedInSupervisedProfile string used for a
* supervised user. Gives information about family link controls and that they
* will not be signed out on clearing cookies
*/
private cookiesCheckboxLabel_(
signedInState: SignedInState,
shouldShowCookieException: boolean,
cookiesSummary: string,
clearCookiesSummarySignedIn: string,
clearCookiesSummarySyncing: string,
// <if expr="is_linux or is_macosx or is_win">
clearCookiesSummarySignedInSupervisedProfile: string,
// </if>
): string {
// <if expr="is_linux or is_macosx or is_win">
if (loadTimeData.getBoolean('isChildAccount')) {
return clearCookiesSummarySignedInSupervisedProfile;
}
// </if>
// The exception is not shown for SIGNED_IN_PAUSED.
if (this.unoDesktopEnabled_ && signedInState === SignedInState.SIGNED_IN) {
return clearCookiesSummarySignedIn;
}
if (shouldShowCookieException) {
return clearCookiesSummarySyncing;
}
// <if expr="chromeos_lacros">
if (!loadTimeData.getBoolean('isSecondaryUser')) {
return loadTimeData.getString('clearCookiesSummarySignedInMainProfile');
}
// </if>
return cookiesSummary;
}
/**
* Updates the text of a browsing data counter corresponding to the given
* preference.
* @param prefName Browsing data type deletion preference.
* @param text The text with which to update the counter
*/
private updateCounterText_(prefName: string, text: string) {
// Data type deletion preferences are named "browser.clear_data.<datatype>".
// Strip the common prefix, i.e. use only "<datatype>".
const matches = prefName.match(/^browser\.clear_data\.(\w+)$/)!;
assert(matches[1]);
this.set('counters_.' + matches[1], text);
}
/**
* @return A list of selected data types.
*/
private getSelectedDataTypes_(page: HTMLElement): string[] {
const checkboxes = page.querySelectorAll('settings-checkbox');
const dataTypes: string[] = [];
checkboxes.forEach((checkbox) => {
if (checkbox.checked && !checkbox.hidden) {
dataTypes.push(checkbox.pref!.key);
}
});
return dataTypes;
}
private getTimeRangeDropdownForCurrentPage_() {
const page = this.$.pages.selectedItem as HTMLElement;
const dropdownMenu =
page.querySelector<SettingsDropdownMenuElement>('.time-range-select');
assert(dropdownMenu);
return dropdownMenu;
}
private isBasicTabSelected_() {
const page = this.$.pages.selectedItem as HTMLElement;
assert(page);
switch (page.id) {
case 'basic-tab':
return true;
case 'advanced-tab':
return false;
default:
assertNotReached();
}
}
// TODO(crbug.com/40283307): Remove this after CbdTimeframeRequired finishes.
/** Highlight the time period dropdown in case no selection was made. */
private validateSelectedTimeRange_(): boolean {
const dropdownMenu = this.getTimeRangeDropdownForCurrentPage_();
const timePeriod = Number(dropdownMenu.getSelectedValue());
if (timePeriod !== TimePeriodExperiment.NOT_SELECTED) {
return true;
}
// No time period is selected: the time period dropdown gets highlighted,
// and no clearing should happen.
dropdownMenu.classList.add('dropdown-error');
// Move the focus to the dropdown. This visually indicates the requirement
// to select a time period, which the dropdown clarifies via the text of its
// current selection. This also allows screen readers to read out this text
// to a11y users to indicate this requirement to them.
dropdownMenu.focus();
return false;
}
// TODO(crbug.com/40283307): Remove once crbug.com/1487530 completed.
private cbdExperimentDualWritePrefs_() {
// To avoid in- and out-of-experiment prefs of the CBD time range experiment
// (crbug.com/1487530) from diverging, the in-experiment prefs should also
// be written to the out-of-experiment prefs. A 15min in-experiment
// selection should be a 1h out-of-experiment selection. Out-of-experiment
// prefs should also be written to the in-experiment prefs iff the in-
// experiment prefs value is not TimePeriodExperiment.NOT_SELECTED.
const dropdownMenuBasic =
this.shadowRoot!.querySelector<SettingsCheckboxElement>(
'#clearFromBasic');
assert(dropdownMenuBasic);
const timeRangeBasic =
dropdownMenuBasic.pref!.value === TimePeriodExperiment.LAST_15_MINUTES ?
TimePeriod.LAST_HOUR :
dropdownMenuBasic.pref!.value;
const dropdownMenuAdvanced =
this.shadowRoot!.querySelector<SettingsCheckboxElement>('#clearFrom');
assert(dropdownMenuAdvanced);
const timeRangeAdvanced = dropdownMenuAdvanced.pref!.value ===
TimePeriodExperiment.LAST_15_MINUTES ?
TimePeriod.LAST_HOUR :
dropdownMenuAdvanced.pref!.value;
if (this.enableCbdTimeframeRequired_) {
this.setPrefValue('browser.clear_data.time_period_basic', timeRangeBasic);
this.setPrefValue('browser.clear_data.time_period', timeRangeAdvanced);
} else {
// Out-of-experiment.
if (this.getPref('browser.clear_data.time_period_v2_basic').value !==
TimePeriodExperiment.NOT_SELECTED) {
this.setPrefValue(
'browser.clear_data.time_period_v2_basic', timeRangeBasic);
}
if (this.getPref('browser.clear_data.time_period_v2').value !==
TimePeriodExperiment.NOT_SELECTED) {
this.setPrefValue(
'browser.clear_data.time_period_v2', timeRangeAdvanced);
}
}
}
/** Clears browsing data and maybe shows a history notice. */
private async clearBrowsingData_() {
if (!this.validateSelectedTimeRange_()) {
return;
}
this.clearingInProgress_ = true;
this.clearingDataAlertString_ = loadTimeData.getString('clearingData');
const page = this.$.pages.selectedItem as HTMLElement;
const dataTypes = this.getSelectedDataTypes_(page);
const dropdownMenu = this.getTimeRangeDropdownForCurrentPage_();
const timePeriod = Number(dropdownMenu.getSelectedValue());
if (this.isBasicTabSelected_()) {
chrome.metricsPrivate.recordUserAction('ClearBrowsingData_BasicTab');
// For users in the CbdTimeframeRequired experiment, the selection should
// only be recorded the first time they clear data. This needs to be
// checked before the selected time range is written to prefs.
if (!this.enableCbdTimeframeRequired_ ||
this.getPref<TimePeriodExperiment>(
'browser.clear_data.time_period_v2_basic')
.value === TimePeriodExperiment.NOT_SELECTED) {
this.browserProxy_
.recordSettingsClearBrowsingDataBasicTimePeriodHistogram(
timePeriod);
}
} else {
// Advanced tab.
chrome.metricsPrivate.recordUserAction('ClearBrowsingData_AdvancedTab');
// For users in the CbdTimeframeRequired experiment, the selection should
// only be recorded the first time they clear data. This needs to be
// checked before the selected time range is written to prefs.
if (!this.enableCbdTimeframeRequired_ ||
this.getPref<TimePeriodExperiment>(
'browser.clear_data.time_period_v2')
.value === TimePeriodExperiment.NOT_SELECTED) {
this.browserProxy_
.recordSettingsClearBrowsingDataAdvancedTimePeriodHistogram(
timePeriod);
}
}
this.setPrefValue(
'browser.last_clear_browsing_data_tab', this.selectedTabIndex_);
// Dropdown menu and checkbox selections of both tabs should be persisted
// independently from the tab on which the user confirmed the deletion.
this.shadowRoot!
.querySelectorAll<SettingsCheckboxElement>(
'settings-checkbox[no-set-pref]')
.forEach(checkbox => checkbox.sendPrefChange());
this.shadowRoot!
.querySelectorAll<SettingsDropdownMenuElement>(
'settings-dropdown-menu[no-set-pref]')
.forEach(dropdown => dropdown.sendPrefChange());
// Dual write prefs only after the regular prefs have been written above.
this.cbdExperimentDualWritePrefs_();
const {showHistoryNotice, showPasswordsNotice} =
await this.browserProxy_.clearBrowsingData(
dataTypes, dropdownMenu.pref!.value);
this.clearingInProgress_ = false;
getAnnouncerInstance().announce(loadTimeData.getString('clearedData'));
this.showHistoryDeletionDialog_ = showHistoryNotice;
// If both the history notice and the passwords notice should be shown, show
// the history notice first, and then show the passwords notice once the
// history notice gets closed.
this.showPasswordsDeletionDialog_ =
showPasswordsNotice && !showHistoryNotice;
this.showPasswordsDeletionDialogLater_ =
showPasswordsNotice && showHistoryNotice;
// Close the clear browsing data if it is open.
const isLastDialog = !showHistoryNotice && !showPasswordsNotice;
if (this.$.clearBrowsingDataDialog.open) {
closeDialog(this.$.clearBrowsingDataDialog, isLastDialog);
}
}
private onCancelClick_() {
this.$.clearBrowsingDataDialog.cancel();
}
/**
* Handles the closing of the notice about other forms of browsing history.
*/
private onHistoryDeletionDialogClose_(e: Event) {
this.showHistoryDeletionDialog_ = false;
if (this.showPasswordsDeletionDialogLater_) {
// Stop the close event from propagating further and also automatically
// closing other dialogs.
e.stopPropagation();
this.showPasswordsDeletionDialogLater_ = false;
this.showPasswordsDeletionDialog_ = true;
}
}
/**
* Handles the closing of the notice about incomplete passwords deletion.
*/
private onPasswordsDeletionDialogClose_() {
this.showPasswordsDeletionDialog_ = false;
}
private onSelectedTabIndexPrefUpdated_(selectedTabIndex: number) {
this.selectedTabIndex_ = selectedTabIndex;
}
/**
* Records an action when the user changes between the basic and advanced tab.
*/
private recordTabChange_(event: CustomEvent<{value: number}>) {
if (event.detail.value === 0) {
chrome.metricsPrivate.recordUserAction(
'ClearBrowsingData_SwitchTo_BasicTab');
} else {
chrome.metricsPrivate.recordUserAction(
'ClearBrowsingData_SwitchTo_AdvancedTab');
}
}
// <if expr="not is_chromeos">
/** Called when the user clicks the link in the footer. */
private onSyncDescriptionLinkClicked_(e: Event) {
if ((e.target as HTMLElement).tagName === 'A') {
e.preventDefault();
if (this.showSigninInfo_()) {
chrome.metricsPrivate.recordUserAction('ClearBrowsingData_SignOut');
this.syncBrowserProxy_.signOut(/*delete_profile=*/ false);
} else if (this.showSyncInfo_()) {
chrome.metricsPrivate.recordUserAction('ClearBrowsingData_Sync_Pause');
this.syncBrowserProxy_.pauseSync();
} else if (this.isSyncPaused_) {
chrome.metricsPrivate.recordUserAction('ClearBrowsingData_Sync_SignIn');
this.syncBrowserProxy_.startSignIn();
} else {
if (this.hasPassphraseError_) {
chrome.metricsPrivate.recordUserAction(
'ClearBrowsingData_Sync_NavigateToPassphrase');
} else {
chrome.metricsPrivate.recordUserAction(
'ClearBrowsingData_Sync_NavigateToError');
}
// In any other error case, navigate to the sync page.
Router.getInstance().navigateTo(routes.SYNC);
}
}
}
private computeIsSyncPaused_(): boolean {
return !!this.syncStatus!.hasError &&
!this.syncStatus!.hasUnrecoverableError &&
this.syncStatus!.statusAction === StatusAction.REAUTHENTICATE;
}
private computeHasPassphraseError_(): boolean {
return !!this.syncStatus!.hasError &&
this.syncStatus!.statusAction === StatusAction.ENTER_PASSPHRASE;
}
private computeHasOtherError_(): boolean {
return this.syncStatus !== undefined && !!this.syncStatus!.hasError &&
!this.isSyncPaused_ && !this.hasPassphraseError_;
}
// </if>
private computeGoogleSearchHistoryString_(isNonGoogleDse: boolean):
TrustedHTML {
return isNonGoogleDse ?
this.i18nAdvanced('clearGoogleSearchHistoryNonGoogleDse') :
this.i18nAdvanced('clearGoogleSearchHistoryGoogleDse');
}
// <if expr="not is_chromeos">
private shouldShowFooter_(): boolean {
if (!!this.syncStatus &&
this.syncStatus.signedInState === SignedInState.SYNCING) {
return true;
}
return this.unoDesktopEnabled_ && this.isClearPrimaryAccountAllowed_ &&
this.isSignedIn_;
}
/**
* @return Whether the signed info description should be shown in the footer.
*/
private showSigninInfo_(): boolean {
return this.unoDesktopEnabled_ && this.isSignedIn_ &&
this.isClearPrimaryAccountAllowed_ &&
(!this.syncStatus ||
this.syncStatus.signedInState !== SignedInState.SYNCING);
}
/**
* @return Whether the synced info description should be shown in the footer.
*/
private showSyncInfo_(): boolean {
return !this.showSigninInfo_() && !!this.syncStatus &&
!this.syncStatus.hasError;
}
// </if>
private onTimePeriodChanged_() {
const dropdownMenu = this.getTimeRangeDropdownForCurrentPage_();
// Needed in the |enableCbdTimeframeRequired_| experiment, no-op otherwise.
// TODO(crbug.com/40283307): Remove when crbug.com/1487530 finished.
dropdownMenu.classList.remove('dropdown-error');
let timePeriod = parseInt(dropdownMenu.getSelectedValue(), 10);
assert(!Number.isNaN(timePeriod));
// If the time period is not selected, count all the data.
if (timePeriod === TimePeriodExperiment.NOT_SELECTED) {
timePeriod = TimePeriodExperiment.ALL_TIME;
}
this.browserProxy_.restartCounters(this.isBasicTabSelected_(), timePeriod);
}
private onTimePeriodAdvancedPrefUpdated_() {
this.onTimePeriodPrefUpdated_(false);
}
private onTimePeriodBasicPrefUpdated_() {
this.onTimePeriodPrefUpdated_(true);
}
private onTimePeriodPrefUpdated_(isBasic: boolean) {
const timePeriodPref = isBasic ? 'browser.clear_data.time_period_basic' :
'browser.clear_data.time_period';
const timePeriodValue = this.getPref(timePeriodPref).value;
if (!(timePeriodValue in TimePeriod)) {
// If the synced time period is not supported, default to "Last hour".
this.setPrefValue(timePeriodPref, TimePeriod.LAST_HOUR);
}
}
}
declare global {
interface HTMLElementTagNameMap {
'settings-clear-browsing-data-dialog':
SettingsClearBrowsingDataDialogElement;
}
}
customElements.define(
SettingsClearBrowsingDataDialogElement.is,
SettingsClearBrowsingDataDialogElement);