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") { ...@@ -106,6 +106,7 @@ js_type_check("settings_resources") {
":focus_row_behavior", ":focus_row_behavior",
":global_scroll_target_behavior", ":global_scroll_target_behavior",
":lifetime_browser_proxy", ":lifetime_browser_proxy",
":list_property_update_behavior",
":page_visibility", ":page_visibility",
":route", ":route",
":search_settings", ":search_settings",
...@@ -133,6 +134,9 @@ js_library("global_scroll_target_behavior") { ...@@ -133,6 +134,9 @@ js_library("global_scroll_target_behavior") {
] ]
} }
js_library("list_property_update_behavior") {
}
js_library("lifetime_browser_proxy") { js_library("lifetime_browser_proxy") {
deps = [ deps = [
"//ui/webui/resources/js:cr", "//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") { ...@@ -82,6 +82,7 @@ js_library("passwords_section") {
":password_list_item", ":password_list_item",
":password_manager_proxy", ":password_manager_proxy",
"..:global_scroll_target_behavior", "..: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_action_menu:cr_action_menu",
"//ui/webui/resources/cr_elements/cr_toast:cr_toast", "//ui/webui/resources/cr_elements/cr_toast:cr_toast",
"//ui/webui/resources/js:assert", "//ui/webui/resources/js:assert",
......
...@@ -32,10 +32,7 @@ Polymer({ ...@@ -32,10 +32,7 @@ Polymer({
/** /**
* Get the aria label for the More Actions button on this row. * Get the aria label for the More Actions button on this row.
* @param {{ * @param {!PasswordManagerProxy.UiEntryWithPassword} item This row's item.
* entry: !chrome.passwordsPrivate.PasswordUiEntry,
* password: string
* }} item This row's item.
* @private * @private
*/ */
getMoreActionsLabel_: function(item) { getMoreActionsLabel_: function(item) {
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
<link rel="import" href="../controls/settings_toggle_button.html"> <link rel="import" href="../controls/settings_toggle_button.html">
<link rel="import" href="../controls/extension_controlled_indicator.html"> <link rel="import" href="../controls/extension_controlled_indicator.html">
<link rel="import" href="../global_scroll_target_behavior.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="../prefs/prefs.html">
<link rel="import" href="../settings_shared_css.html"> <link rel="import" href="../settings_shared_css.html">
<link rel="import" href="password_edit_dialog.html"> <link rel="import" href="password_edit_dialog.html">
...@@ -103,7 +104,7 @@ ...@@ -103,7 +104,7 @@
</div> </div>
<div class="list-frame"> <div class="list-frame">
<div id="savedPasswordsHeading" class="list-item column-header" <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="website-column">$i18n{editPasswordWebsiteLabel}</div>
<div class="username-column"> <div class="username-column">
$i18n{editPasswordUsernameLabel} $i18n{editPasswordUsernameLabel}
...@@ -113,7 +114,7 @@ ...@@ -113,7 +114,7 @@
</div> </div>
</div> </div>
<iron-list id="passwordList" preserve-focus <iron-list id="passwordList" preserve-focus
items="[[getFilteredPasswords_(savedPasswords, filter)]]" items="[[getFilteredPasswords_(filter, savedPasswords.splices)]]"
class="cr-separators list-with-header" class="cr-separators list-with-header"
scroll-target="[[subpageScrollTarget]]" risk-selection> scroll-target="[[subpageScrollTarget]]" risk-selection>
<template> <template>
...@@ -124,7 +125,7 @@ ...@@ -124,7 +125,7 @@
</template> </template>
</iron-list> </iron-list>
<div id="noPasswordsLabel" class="list-item" <div id="noPasswordsLabel" class="list-item"
hidden$="[[hasSome_(savedPasswords)]]"> hidden$="[[hasSome_(savedPasswords, savedPasswords.splices)]]">
$i18n{noPasswordsFound} $i18n{noPasswordsFound}
</div> </div>
</div> </div>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* save any passwords. * save any passwords.
*/ */
/** @typedef {!{model: !{item: !chrome.passwordsPrivate.PasswordUiEntry}}} */ /** @typedef {!{model: !{item: !PasswordManagerProxy.UiEntryWithPassword}}} */
let PasswordUiEntryEvent; let PasswordUiEntryEvent;
/** @typedef {!{model: !{item: !chrome.passwordsPrivate.ExceptionEntry}}} */ /** @typedef {!{model: !{item: !chrome.passwordsPrivate.ExceptionEntry}}} */
...@@ -22,6 +22,7 @@ Polymer({ ...@@ -22,6 +22,7 @@ Polymer({
behaviors: [ behaviors: [
I18nBehavior, I18nBehavior,
ListPropertyUpdateBehavior,
Polymer.IronA11yKeysBehavior, Polymer.IronA11yKeysBehavior,
settings.GlobalScrollTargetBehavior, settings.GlobalScrollTargetBehavior,
], ],
...@@ -35,15 +36,21 @@ Polymer({ ...@@ -35,15 +36,21 @@ Polymer({
/** /**
* An array of passwords to display. * 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. * An array of sites to display.
* @type {!Array<!PasswordManagerProxy.ExceptionEntry>} * @type {!Array<!PasswordManagerProxy.ExceptionEntry>}
*/ */
passwordExceptions: Array, passwordExceptions: {
type: Array,
value: [],
},
/** /**
* Duration of the undo toast in ms * Duration of the undo toast in ms
...@@ -76,7 +83,7 @@ Polymer({ ...@@ -76,7 +83,7 @@ Polymer({
/** @private */ /** @private */
showExportPasswords_: { showExportPasswords_: {
type: Boolean, type: Boolean,
computed: 'showExportPasswordsAndReady_(savedPasswords)' computed: 'showExportPasswordsAndReady_(savedPasswords.splices)'
}, },
/** @private */ /** @private */
...@@ -97,7 +104,7 @@ Polymer({ ...@@ -97,7 +104,7 @@ Polymer({
value: '', value: '',
}, },
/** @private {!PasswordManagerProxy.PasswordUiEntry} */ /** @private {!PasswordManagerProxy.UiEntryWithPassword} */
lastFocused_: Object, lastFocused_: Object,
}, },
...@@ -144,14 +151,13 @@ Polymer({ ...@@ -144,14 +151,13 @@ Polymer({
/** @override */ /** @override */
attached: function() { attached: function() {
// Create listener functions. // Create listener functions.
const setSavedPasswordsListener = list => { const setSavedPasswordsListener = list => this.updateList(
this.savedPasswords = list.map(entry => { 'savedPasswords',
return { item => `${item.entry.index}_${item.entry.loginPair.urls.shown}`,
entry: entry, list.map(entry => ({
password: '', entry: entry,
}; password: '',
}); })));
};
const setPasswordExceptionsListener = list => { const setPasswordExceptionsListener = list => {
this.passwordExceptions = list; this.passwordExceptions = list;
...@@ -218,19 +224,17 @@ Polymer({ ...@@ -218,19 +224,17 @@ Polymer({
}, },
/** /**
* @param {!Array<!PasswordManagerProxy.UiEntryWithPassword>} savedPasswords
* @param {string} filter * @param {string} filter
* @return {!Array<!PasswordManagerProxy.UiEntryWithPassword>} * @return {!Array<!PasswordManagerProxy.UiEntryWithPassword>}
* @private * @private
*/ */
getFilteredPasswords_: function(savedPasswords, filter) { getFilteredPasswords_: function(filter) {
if (!filter) if (!filter)
return savedPasswords; return this.savedPasswords.slice();
return savedPasswords.filter(p => { return this.savedPasswords.filter(
return [p.entry.loginPair.urls.shown, p.entry.loginPair.username].some( p => [p.entry.loginPair.urls.shown, p.entry.loginPair.username].some(
term => term.toLowerCase().includes(filter.toLowerCase())); term => term.toLowerCase().includes(filter.toLowerCase())));
});
}, },
/** /**
...@@ -239,9 +243,8 @@ Polymer({ ...@@ -239,9 +243,8 @@ Polymer({
* @private * @private
*/ */
passwordExceptionFilter_: function(filter) { passwordExceptionFilter_: function(filter) {
return function(exception) { return exception => exception.urls.shown.toLowerCase().includes(
return exception.urls.shown.toLowerCase().includes(filter.toLowerCase()); filter.toLowerCase());
};
}, },
/** /**
...@@ -365,14 +368,11 @@ Polymer({ ...@@ -365,14 +368,11 @@ Polymer({
return toggleValue ? this.i18n('toggleOn') : this.i18n('toggleOff'); return toggleValue ? this.i18n('toggleOn') : this.i18n('toggleOff');
}, },
/** /** @private */
* @private showExportPasswordsAndReady_: function() {
* @param {!Array<!PasswordManagerProxy.PasswordUiEntry>} savedPasswords
*/
showExportPasswordsAndReady_: function(savedPasswords) {
return loadTimeData.valueExists('showExportPasswords') && return loadTimeData.valueExists('showExportPasswords') &&
loadTimeData.getBoolean('showExportPasswords') && loadTimeData.getBoolean('showExportPasswords') &&
savedPasswords.length > 0; this.savedPasswords.length > 0;
}, },
/** /**
......
...@@ -295,6 +295,12 @@ ...@@ -295,6 +295,12 @@
<structure name="IDR_SETTINGS_GLOBAL_SCROLL_TARGET_BEHAVIOR_JS" <structure name="IDR_SETTINGS_GLOBAL_SCROLL_TARGET_BEHAVIOR_JS"
file="global_scroll_target_behavior.js" file="global_scroll_target_behavior.js"
type="chrome_html" /> 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" <structure name="IDR_SETTINGS_FOCUS_ROW_BEHAVIOR_HTML"
file="focus_row_behavior.html" file="focus_row_behavior.html"
type="chrome_html" /> type="chrome_html" />
......
...@@ -124,6 +124,7 @@ js_library("site_data") { ...@@ -124,6 +124,7 @@ js_library("site_data") {
":local_data_browser_proxy", ":local_data_browser_proxy",
":site_settings_behavior", ":site_settings_behavior",
"..:global_scroll_target_behavior", "..:global_scroll_target_behavior",
"..:list_property_update_behavior",
"../settings_page:settings_subpage_search", "../settings_page:settings_subpage_search",
"//ui/webui/resources/js:assert", "//ui/webui/resources/js:assert",
"//ui/webui/resources/js:cr", "//ui/webui/resources/js:cr",
......
...@@ -11,6 +11,7 @@ ...@@ -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-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="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
<link rel="import" href="../global_scroll_target_behavior.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_page/settings_subpage_search.html">
<link rel="import" href="../settings_shared_css.html"> <link rel="import" href="../settings_shared_css.html">
<link rel="import" href="cookie_info.html"> <link rel="import" href="cookie_info.html">
...@@ -50,7 +51,7 @@ ...@@ -50,7 +51,7 @@
[[computeRemoveLabel_(filter)]] [[computeRemoveLabel_(filter)]]
</paper-button> </paper-button>
</div> </div>
<iron-list id="list" items="[[sites]]" <iron-list id="list" items="[[sites]]" preserve-focus
scroll-target="[[subpageScrollTarget]]"> scroll-target="[[subpageScrollTarget]]">
<template> <template>
<div class="settings-box two-line site-item" first$="[[!index]]" <div class="settings-box two-line site-item" first$="[[!index]]"
......
...@@ -40,6 +40,7 @@ Polymer({ ...@@ -40,6 +40,7 @@ Polymer({
behaviors: [ behaviors: [
I18nBehavior, I18nBehavior,
ListPropertyUpdateBehavior,
settings.GlobalScrollTargetBehavior, settings.GlobalScrollTargetBehavior,
WebUIListenerBehavior, WebUIListenerBehavior,
], ],
...@@ -145,8 +146,8 @@ Polymer({ ...@@ -145,8 +146,8 @@ Polymer({
*/ */
updateSiteList_: function() { updateSiteList_: function() {
this.isLoading_ = true; this.isLoading_ = true;
this.browserProxy_.getDisplayList(this.filter).then((listInfo) => { this.browserProxy_.getDisplayList(this.filter).then(listInfo => {
this.sites = listInfo.items; this.updateList('sites', item => item.site, listInfo.items);
this.isLoading_ = false; this.isLoading_ = false;
this.fire('site-data-list-complete'); this.fire('site-data-list-complete');
}); });
......
...@@ -114,7 +114,7 @@ TEST_F('SettingsPasswordSectionBrowserTest', 'uiTests', function() { ...@@ -114,7 +114,7 @@ TEST_F('SettingsPasswordSectionBrowserTest', 'uiTests', function() {
* @private * @private
*/ */
function flushPasswordSection(passwordsSection) { function flushPasswordSection(passwordsSection) {
passwordsSection.$.passwordList.notifyResize(); passwordsSection.notifySplices('savedPasswords');
Polymer.dom.flush(); 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