1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 cr.define('options', function() {
6 /** @const */ var OptionsPage = options.OptionsPage;
7 /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel;
9 /////////////////////////////////////////////////////////////////////////////
10 // PasswordManager class:
13 * Encapsulated handling of password and exceptions page.
16 function PasswordManager() {
17 this.activeNavTab = null;
18 OptionsPage.call(this,
20 loadTimeData.getString('passwordsPageTabTitle'),
24 cr.addSingletonGetter(PasswordManager);
26 PasswordManager.prototype = {
27 __proto__: OptionsPage.prototype,
30 * The saved passwords list.
31 * @type {DeletableItemList}
34 savedPasswordsList_: null,
37 * The password exceptions list.
38 * @type {DeletableItemList}
41 passwordExceptionsList_: null,
44 * The timer id of the timer set on search query change events.
48 queryDelayTimerId_: 0,
51 * The most recent search query, or null if the query is empty.
58 initializePage: function() {
59 OptionsPage.prototype.initializePage.call(this);
61 $('password-manager-confirm').onclick = function() {
62 OptionsPage.closeOverlay();
65 $('password-search-box').addEventListener('search',
66 this.handleSearchQueryChange_.bind(this));
68 this.createSavedPasswordsList_();
69 this.createPasswordExceptionsList_();
73 canShowPage: function() {
74 return !(cr.isChromeOS && UIAccountTweaks.loggedInAsGuest());
78 didShowPage: function() {
79 // Updating the password lists may cause a blocking platform dialog pop up
80 // (Mac, Linux), so we delay this operation until the page is shown.
81 chrome.send('updatePasswordLists');
82 $('password-search-box').focus();
86 * Creates, decorates and initializes the saved passwords list.
89 createSavedPasswordsList_: function() {
90 this.savedPasswordsList_ = $('saved-passwords-list');
91 options.passwordManager.PasswordsList.decorate(this.savedPasswordsList_);
92 this.savedPasswordsList_.autoExpands = true;
96 * Creates, decorates and initializes the password exceptions list.
99 createPasswordExceptionsList_: function() {
100 this.passwordExceptionsList_ = $('password-exceptions-list');
101 options.passwordManager.PasswordExceptionsList.decorate(
102 this.passwordExceptionsList_);
103 this.passwordExceptionsList_.autoExpands = true;
107 * Handles search query changes.
108 * @param {!Event} e The event object.
111 handleSearchQueryChange_: function(e) {
112 if (this.queryDelayTimerId_)
113 window.clearTimeout(this.queryDelayTimerId_);
115 // Searching cookies uses a timeout of 500ms. We use a shorter timeout
116 // because there are probably fewer passwords and we want the UI to be
117 // snappier since users will expect that it's "less work."
118 this.queryDelayTimerId_ = window.setTimeout(
119 this.searchPasswords_.bind(this), 250);
123 * Search passwords using text in |password-search-box|.
126 searchPasswords_: function() {
127 this.queryDelayTimerId_ = 0;
128 var filter = $('password-search-box').value;
129 filter = (filter == '') ? null : filter;
130 if (this.lastQuery_ != filter) {
131 this.lastQuery_ = filter;
132 // Searching for passwords has the side effect of requerying the
133 // underlying password store. This is done intentionally, as on OS X and
134 // Linux they can change from outside and we won't be notified of it.
135 chrome.send('updatePasswordLists');
140 * Updates the visibility of the list and empty list placeholder.
141 * @param {!List} list The list to toggle visilibility for.
143 updateListVisibility_: function(list) {
144 var empty = list.dataModel.length == 0;
145 var listPlaceHolderID = list.id + '-empty-placeholder';
147 $(listPlaceHolderID).hidden = !empty;
151 * Updates the data model for the saved passwords list with the values from
153 * @param {Array} entries The list of saved password data.
155 setSavedPasswordsList_: function(entries) {
156 if (this.lastQuery_) {
157 // Implement password searching here in javascript, rather than in C++.
158 // The number of saved passwords shouldn't be too big for us to handle.
159 var query = this.lastQuery_;
160 var filter = function(entry, index, list) {
161 // Search both URL and username.
162 if (entry[0].toLowerCase().indexOf(query.toLowerCase()) >= 0 ||
163 entry[1].toLowerCase().indexOf(query.toLowerCase()) >= 0) {
164 // Keep the original index so we can delete correctly. See also
165 // deleteItemAtIndex() in password_manager_list.js that uses this.
171 entries = entries.filter(filter);
173 this.savedPasswordsList_.dataModel = new ArrayDataModel(entries);
174 this.updateListVisibility_(this.savedPasswordsList_);
178 * Updates the data model for the password exceptions list with the values
180 * @param {Array} entries The list of password exception data.
182 setPasswordExceptionsList_: function(entries) {
183 this.passwordExceptionsList_.dataModel = new ArrayDataModel(entries);
184 this.updateListVisibility_(this.passwordExceptionsList_);
188 * Reveals the password for a saved password entry. This is called by the
189 * backend after it has authenticated the user.
190 * @param {number} index The original index of the entry in the model.
191 * @param {string} password The saved password.
193 showPassword_: function(index, password) {
194 var model = this.savedPasswordsList_.dataModel;
195 if (this.lastQuery_) {
196 // When a filter is active, |index| does not represent the current
197 // index in the model, but each entry stores its original index, so
198 // we can find the item using a linear search.
199 for (var i = 0; i < model.length; ++i) {
200 if (model.item(i)[3] == index) {
207 // Reveal the password in the UI.
208 var item = this.savedPasswordsList_.getListItemByIndex(index);
209 item.showPassword(password);
214 * Removes a saved password.
215 * @param {number} rowIndex indicating the row to remove.
217 PasswordManager.removeSavedPassword = function(rowIndex) {
218 chrome.send('removeSavedPassword', [String(rowIndex)]);
222 * Removes a password exception.
223 * @param {number} rowIndex indicating the row to remove.
225 PasswordManager.removePasswordException = function(rowIndex) {
226 chrome.send('removePasswordException', [String(rowIndex)]);
229 PasswordManager.requestShowPassword = function(index) {
230 chrome.send('requestShowPassword', [index]);
233 // Forward public APIs to private implementations on the singleton instance.
235 'setSavedPasswordsList',
236 'setPasswordExceptionsList',
238 ].forEach(function(name) {
239 PasswordManager[name] = function() {
240 var instance = PasswordManager.getInstance();
241 return instance[name + '_'].apply(instance, arguments);
247 PasswordManager: PasswordManager