Commit 79911889 authored by Esmael El-Moslimany's avatar Esmael El-Moslimany Committed by Commit Bot

Settings: update a list property with splices and use notifySplices to notify once

Bug: 836303
Cq-Include-Trybots: master.tryserver.chromium.linux:closure_compilation
Change-Id: Ia90801ff9d33b92d31abea4b3f65ad189d8cb72c
Reviewed-on: https://chromium-review.googlesource.com/1044764Reviewed-by: default avatarScott Chen <scottchen@chromium.org>
Reviewed-by: default avatarDemetrios Papadopoulos <dpapad@chromium.org>
Commit-Queue: Esmael El-Moslimany <aee@chromium.org>
Cr-Commit-Position: refs/heads/master@{#557337}
parent 1ed85133
......@@ -106,6 +106,7 @@ js_type_check("settings_resources") {
":focus_row_behavior",
":global_scroll_target_behavior",
":lifetime_browser_proxy",
":list_property_update_behavior",
":page_visibility",
":route",
":search_settings",
......@@ -133,6 +134,9 @@ js_library("global_scroll_target_behavior") {
]
}
js_library("list_property_update_behavior") {
}
js_library("lifetime_browser_proxy") {
deps = [
"//ui/webui/resources/js:cr",
......
<script src="list_property_update_behavior.js"></script>
// 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 |ListPropertyUpdateBehavior| is used to update an existing
* polymer list property given the list after all the edits were made while
* maintaining the reference to the original list. This allows
* dom-repeat/iron-list elements bound to this list property to not fully
* re-rendered from scratch.
*
* The minimal splices needed to transform the original list to the edited list
* are calculated using |Polymer.ArraySplice.calculateSplices|. All the edits
* are then applied to the original list. Once completed, a single notification
* containing information about all the edits is sent to the polyer object.
*/
/** @polymerBehavior */
const ListPropertyUpdateBehavior = {
/**
* @param {string} propertyName
* @param {function(!Object): string} itemUidGetter
* @param {!Array<!Object>} updatedList
*/
updateList: function(propertyName, itemUidGetter, updatedList) {
const list = this[propertyName];
const splices = Polymer.ArraySplice.calculateSplices(
updatedList.map(itemUidGetter), list.map(itemUidGetter));
splices.forEach(splice => {
const index = splice.index;
const deleteCount = splice.removed.length;
// Transform splices to the expected format of notifySplices().
// Convert !Array<string> to !Array<!Object>.
splice.removed = list.slice(index, index + deleteCount);
splice.object = list;
splice.type = 'splice';
const added = updatedList.slice(index, index + splice.addedCount);
const spliceParams = [index, deleteCount].concat(added);
list.splice.apply(list, spliceParams);
});
if (splices.length > 0)
this.notifySplices(propertyName, splices);
},
};
......@@ -82,6 +82,7 @@ js_library("passwords_section") {
":password_list_item",
":password_manager_proxy",
"..:global_scroll_target_behavior",
"..:list_property_update_behavior",
"//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu",
"//ui/webui/resources/cr_elements/cr_toast:cr_toast",
"//ui/webui/resources/js:assert",
......
......@@ -32,10 +32,7 @@ Polymer({
/**
* Get the aria label for the More Actions button on this row.
* @param {{
* entry: !chrome.passwordsPrivate.PasswordUiEntry,
* password: string
* }} item This row's item.
* @param {!PasswordManagerProxy.UiEntryWithPassword} item This row's item.
* @private
*/
getMoreActionsLabel_: function(item) {
......
......@@ -12,6 +12,7 @@
<link rel="import" href="../controls/settings_toggle_button.html">
<link rel="import" href="../controls/extension_controlled_indicator.html">
<link rel="import" href="../global_scroll_target_behavior.html">
<link rel="import" href="../list_property_update_behavior.html">
<link rel="import" href="../prefs/prefs.html">
<link rel="import" href="../settings_shared_css.html">
<link rel="import" href="password_edit_dialog.html">
......@@ -103,7 +104,7 @@
</div>
<div class="list-frame">
<div id="savedPasswordsHeading" class="list-item column-header"
hidden$="[[!hasSome_(savedPasswords)]]">
hidden$="[[!hasSome_(savedPasswords, savedPasswords.splices)]]">
<div class="website-column">$i18n{editPasswordWebsiteLabel}</div>
<div class="username-column">
$i18n{editPasswordUsernameLabel}
......@@ -113,7 +114,7 @@
</div>
</div>
<iron-list id="passwordList" preserve-focus
items="[[getFilteredPasswords_(savedPasswords, filter)]]"
items="[[getFilteredPasswords_(filter, savedPasswords.splices)]]"
class="cr-separators list-with-header"
scroll-target="[[subpageScrollTarget]]" risk-selection>
<template>
......@@ -124,7 +125,7 @@
</template>
</iron-list>
<div id="noPasswordsLabel" class="list-item"
hidden$="[[hasSome_(savedPasswords)]]">
hidden$="[[hasSome_(savedPasswords, savedPasswords.splices)]]">
$i18n{noPasswordsFound}
</div>
</div>
......
......@@ -8,7 +8,7 @@
* save any passwords.
*/
/** @typedef {!{model: !{item: !chrome.passwordsPrivate.PasswordUiEntry}}} */
/** @typedef {!{model: !{item: !PasswordManagerProxy.UiEntryWithPassword}}} */
let PasswordUiEntryEvent;
/** @typedef {!{model: !{item: !chrome.passwordsPrivate.ExceptionEntry}}} */
......@@ -22,6 +22,7 @@ Polymer({
behaviors: [
I18nBehavior,
ListPropertyUpdateBehavior,
Polymer.IronA11yKeysBehavior,
settings.GlobalScrollTargetBehavior,
],
......@@ -35,15 +36,21 @@ Polymer({
/**
* An array of passwords to display.
* @type {!Array<!PasswordManagerProxy.PasswordUiEntry>}
* @type {!Array<!PasswordManagerProxy.UiEntryWithPassword>}
*/
savedPasswords: Array,
savedPasswords: {
type: Array,
value: [],
},
/**
* An array of sites to display.
* @type {!Array<!PasswordManagerProxy.ExceptionEntry>}
*/
passwordExceptions: Array,
passwordExceptions: {
type: Array,
value: [],
},
/**
* Duration of the undo toast in ms
......@@ -76,7 +83,7 @@ Polymer({
/** @private */
showExportPasswords_: {
type: Boolean,
computed: 'showExportPasswordsAndReady_(savedPasswords)'
computed: 'showExportPasswordsAndReady_(savedPasswords.splices)'
},
/** @private */
......@@ -97,7 +104,7 @@ Polymer({
value: '',
},
/** @private {!PasswordManagerProxy.PasswordUiEntry} */
/** @private {!PasswordManagerProxy.UiEntryWithPassword} */
lastFocused_: Object,
},
......@@ -144,14 +151,13 @@ Polymer({
/** @override */
attached: function() {
// Create listener functions.
const setSavedPasswordsListener = list => {
this.savedPasswords = list.map(entry => {
return {
entry: entry,
password: '',
};
});
};
const setSavedPasswordsListener = list => this.updateList(
'savedPasswords',
item => `${item.entry.index}_${item.entry.loginPair.urls.shown}`,
list.map(entry => ({
entry: entry,
password: '',
})));
const setPasswordExceptionsListener = list => {
this.passwordExceptions = list;
......@@ -218,19 +224,17 @@ Polymer({
},
/**
* @param {!Array<!PasswordManagerProxy.UiEntryWithPassword>} savedPasswords
* @param {string} filter
* @return {!Array<!PasswordManagerProxy.UiEntryWithPassword>}
* @private
*/
getFilteredPasswords_: function(savedPasswords, filter) {
getFilteredPasswords_: function(filter) {
if (!filter)
return savedPasswords;
return this.savedPasswords.slice();
return savedPasswords.filter(p => {
return [p.entry.loginPair.urls.shown, p.entry.loginPair.username].some(
term => term.toLowerCase().includes(filter.toLowerCase()));
});
return this.savedPasswords.filter(
p => [p.entry.loginPair.urls.shown, p.entry.loginPair.username].some(
term => term.toLowerCase().includes(filter.toLowerCase())));
},
/**
......@@ -239,9 +243,8 @@ Polymer({
* @private
*/
passwordExceptionFilter_: function(filter) {
return function(exception) {
return exception.urls.shown.toLowerCase().includes(filter.toLowerCase());
};
return exception => exception.urls.shown.toLowerCase().includes(
filter.toLowerCase());
},
/**
......@@ -365,14 +368,11 @@ Polymer({
return toggleValue ? this.i18n('toggleOn') : this.i18n('toggleOff');
},
/**
* @private
* @param {!Array<!PasswordManagerProxy.PasswordUiEntry>} savedPasswords
*/
showExportPasswordsAndReady_: function(savedPasswords) {
/** @private */
showExportPasswordsAndReady_: function() {
return loadTimeData.valueExists('showExportPasswords') &&
loadTimeData.getBoolean('showExportPasswords') &&
savedPasswords.length > 0;
this.savedPasswords.length > 0;
},
/**
......
......@@ -295,6 +295,12 @@
<structure name="IDR_SETTINGS_GLOBAL_SCROLL_TARGET_BEHAVIOR_JS"
file="global_scroll_target_behavior.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_LIST_PROPERTY_UPDATE_BEHAVIOR_HTML"
file="list_property_update_behavior.html"
type="chrome_html" />
<structure name="IDR_SETTINGS_LIST_PROPERTY_UPDATE_BEHAVIOR_JS"
file="list_property_update_behavior.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_FOCUS_ROW_BEHAVIOR_HTML"
file="focus_row_behavior.html"
type="chrome_html" />
......
......@@ -124,6 +124,7 @@ js_library("site_data") {
":local_data_browser_proxy",
":site_settings_behavior",
"..:global_scroll_target_behavior",
"..:list_property_update_behavior",
"../settings_page:settings_subpage_search",
"//ui/webui/resources/js:assert",
"//ui/webui/resources/js:cr",
......
......@@ -11,6 +11,7 @@
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
<link rel="import" href="../global_scroll_target_behavior.html">
<link rel="import" href="../list_property_update_behavior.html">
<link rel="import" href="../settings_page/settings_subpage_search.html">
<link rel="import" href="../settings_shared_css.html">
<link rel="import" href="cookie_info.html">
......@@ -50,7 +51,7 @@
[[computeRemoveLabel_(filter)]]
</paper-button>
</div>
<iron-list id="list" items="[[sites]]"
<iron-list id="list" items="[[sites]]" preserve-focus
scroll-target="[[subpageScrollTarget]]">
<template>
<div class="settings-box two-line site-item" first$="[[!index]]"
......
......@@ -40,6 +40,7 @@ Polymer({
behaviors: [
I18nBehavior,
ListPropertyUpdateBehavior,
settings.GlobalScrollTargetBehavior,
WebUIListenerBehavior,
],
......@@ -145,8 +146,8 @@ Polymer({
*/
updateSiteList_: function() {
this.isLoading_ = true;
this.browserProxy_.getDisplayList(this.filter).then((listInfo) => {
this.sites = listInfo.items;
this.browserProxy_.getDisplayList(this.filter).then(listInfo => {
this.updateList('sites', item => item.site, listInfo.items);
this.isLoading_ = false;
this.fire('site-data-list-complete');
});
......
......@@ -114,7 +114,7 @@ TEST_F('SettingsPasswordSectionBrowserTest', 'uiTests', function() {
* @private
*/
function flushPasswordSection(passwordsSection) {
passwordsSection.$.passwordList.notifyResize();
passwordsSection.notifySplices('savedPasswords');
Polymer.dom.flush();
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment