blob: 9d9d56c2080be6b427065f373165f22c725ef73a [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
* 'site-data' handles showing the local storage summary list for all sites.
*/
/**
* @typedef {{
* site: string,
* id: string,
* localData: string,
* }}
*/
let CookieDataSummaryItem;
/**
* @typedef {{
* id: string,
* start: number,
* count: number,
* }}
*/
let CookieRemovePacket;
Polymer({
is: 'site-data',
behaviors: [
I18nBehavior,
ListPropertyUpdateBehavior,
settings.GlobalScrollTargetBehavior,
WebUIListenerBehavior,
],
properties: {
/**
* The current filter applied to the cookie data list.
*/
filter: {
observer: 'updateSiteList_',
notify: true,
type: String,
},
/** @type {!Map<string, (string|Function)>} */
focusConfig: {
type: Object,
observer: 'focusConfigChanged_',
},
isLoading_: Boolean,
/** @type {!Array<!CookieDataSummaryItem>} */
sites: {
type: Array,
value: function() {
return [];
},
},
/**
* settings.GlobalScrollTargetBehavior
* @override
*/
subpageRoute: {
type: Object,
value: settings.routes.SITE_SETTINGS_SITE_DATA,
},
/** @private */
lastFocused_: Object,
},
/** @private {settings.LocalDataBrowserProxy} */
browserProxy_: null,
/**
* When navigating to site data details sub-page, |lastSelected_| holds the
* site name as well as the index of the selected site. This is used when
* navigating back to site data in order to focus on the correct site.
* @private {!{item: CookieDataSummaryItem, index: number}|null}
*/
lastSelected_: null,
/** @override */
ready: function() {
this.browserProxy_ = settings.LocalDataBrowserProxyImpl.getInstance();
this.addWebUIListener(
'on-tree-item-removed', this.updateSiteList_.bind(this));
},
/**
* Reload cookies when the site data page is visited.
*
* settings.RouteObserverBehavior
* @param {!settings.Route} currentRoute
* @protected
*/
currentRouteChanged: function(currentRoute) {
settings.GlobalScrollTargetBehaviorImpl.currentRouteChanged.call(
this, currentRoute);
if (currentRoute == settings.routes.SITE_SETTINGS_SITE_DATA) {
this.isLoading_ = true;
// Needed to fix iron-list rendering issue. The list will not render
// correctly until a scroll occurs.
// See https://crbug.com/853906.
const ironList = /** @type {!IronListElement} */ (this.$$('iron-list'));
ironList.scrollToIndex(0);
this.browserProxy_.reloadCookies().then(this.updateSiteList_.bind(this));
}
},
/**
* @param {!Map<string, (string|Function)>} newConfig
* @param {?Map<string, (string|Function)>} oldConfig
* @private
*/
focusConfigChanged_: function(newConfig, oldConfig) {
// focusConfig is set only once on the parent, so this observer should only
// fire once.
assert(!oldConfig);
// Populate the |focusConfig| map of the parent <settings-animated-pages>
// element, with additional entries that correspond to subpage trigger
// elements residing in this element's Shadow DOM.
if (settings.routes.SITE_SETTINGS_DATA_DETAILS) {
const onNavigatedTo = () => this.async(() => {
if (this.lastSelected_ == null || this.sites.length == 0)
return;
const lastSelectedSite = this.lastSelected_.item.site;
const lastSelectedIndex = this.lastSelected_.index;
this.lastSelected_ = null;
const indexFromId =
this.sites.findIndex(site => site.site == lastSelectedSite);
// If the site is no longer in |sites|, use the index as a fallback.
// Since the sites are sorted, an alternative could be to select the
// site that comes next in sort order.
const indexFallback = lastSelectedIndex < this.sites.length ?
lastSelectedIndex :
this.sites.length - 1;
const index = indexFromId > -1 ? indexFromId : indexFallback;
this.focusOnSiteSelectButton_(index);
});
this.focusConfig.set(
settings.routes.SITE_SETTINGS_DATA_DETAILS.path, onNavigatedTo);
}
},
/**
* @param {number} index
* @private
*/
focusOnSiteSelectButton_: function(index) {
const ironList =
/** @type {!IronListElement} */ (this.$$('iron-list'));
ironList.focusItem(index);
const siteToSelect = this.sites[index].site.replace(/[.]/g, '\\.');
const button =
this.$$(`#siteItem_${siteToSelect}`).$$('.subpage-arrow button');
cr.ui.focusWithoutInk(assert(button));
},
/**
* Gather all the site data.
* @private
*/
updateSiteList_: function() {
this.isLoading_ = true;
this.browserProxy_.getDisplayList(this.filter).then(listInfo => {
this.updateList(
'sites', item => `${item.site}_${item.localData}`, listInfo.items);
this.isLoading_ = false;
this.fire('site-data-list-complete');
});
},
/**
* Returns the string to use for the Remove label.
* @param {string} filter The current filter string.
* @return {string}
* @private
*/
computeRemoveLabel_: function(filter) {
if (filter.length == 0)
return loadTimeData.getString('siteSettingsCookieRemoveAll');
return loadTimeData.getString('siteSettingsCookieRemoveAllShown');
},
/** @private */
onCloseDialog_: function() {
this.$.confirmDeleteDialog.close();
},
/** @private */
onConfirmDeleteDialogClosed_: function() {
cr.ui.focusWithoutInk(assert(this.$.removeShowingSites));
},
/**
* Shows a dialog to confirm the deletion of multiple sites.
* @param {!Event} e
* @private
*/
onRemoveShowingSitesTap_: function(e) {
e.preventDefault();
this.$.confirmDeleteDialog.showModal();
},
/**
* Called when deletion for all showing sites has been confirmed.
* @private
*/
onConfirmDelete_: function() {
this.$.confirmDeleteDialog.close();
if (this.filter.length == 0) {
this.browserProxy_.removeAll().then(() => {
this.sites = [];
});
} else {
this.browserProxy_.removeShownItems();
// We just deleted all items found by the filter, let's reset the filter.
this.fire('clear-subpage-search');
}
},
/**
* @param {!{model: !{item: CookieDataSummaryItem, index: number}}} event
* @private
*/
onSiteClick_: function(event) {
// If any delete button is selected, the focus will be in a bad state when
// returning to this page. To avoid this, the site select button is given
// focus. See https://crbug.com/872197.
this.focusOnSiteSelectButton_(event.model.index);
settings.navigateTo(
settings.routes.SITE_SETTINGS_DATA_DETAILS,
new URLSearchParams('site=' + event.model.item.site));
this.lastSelected_ = event.model;
},
});