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 Page = cr.ui.pageManager.Page;
7 /** @const */ var PageManager = cr.ui.pageManager.PageManager;
8 /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel;
10 /////////////////////////////////////////////////////////////////////////////
11 // PasswordManager class:
14 * Encapsulated handling of password and exceptions page.
16 * @extends {cr.ui.pageManager.Page}
18 function PasswordManager() {
19 this.activeNavTab = null;
20 Page.call(this, 'passwords',
21 loadTimeData.getString('passwordsPageTabTitle'),
25 cr.addSingletonGetter(PasswordManager);
27 PasswordManager.prototype = {
28 __proto__: Page.prototype,
31 * The saved passwords list.
32 * @type {options.DeletableItemList}
35 savedPasswordsList_: null,
38 * The password exceptions list.
39 * @type {options.DeletableItemList}
42 passwordExceptionsList_: null,
45 * The timer id of the timer set on search query change events.
49 queryDelayTimerId_: 0,
52 * The most recent search query, or null if the query is empty.
59 initializePage: function() {
60 Page.prototype.initializePage.call(this);
62 $('password-manager-confirm').onclick = function() {
63 PageManager.closeOverlay();
66 $('password-search-box').addEventListener('search',
67 this.handleSearchQueryChange_.bind(this));
69 this.createSavedPasswordsList_();
70 this.createPasswordExceptionsList_();
74 canShowPage: function() {
75 return !(cr.isChromeOS && UIAccountTweaks.loggedInAsGuest());
79 didShowPage: function() {
80 // Updating the password lists may cause a blocking platform dialog pop up
81 // (Mac, Linux), so we delay this operation until the page is shown.
82 chrome.send('updatePasswordLists');
83 $('password-search-box').focus();
87 * Creates, decorates and initializes the saved passwords list.
90 createSavedPasswordsList_: function() {
91 this.savedPasswordsList_ = $('saved-passwords-list');
92 options.passwordManager.PasswordsList.decorate(this.savedPasswordsList_);
93 this.savedPasswordsList_.autoExpands = true;
97 * Creates, decorates and initializes the password exceptions list.
100 createPasswordExceptionsList_: function() {
101 this.passwordExceptionsList_ = $('password-exceptions-list');
102 options.passwordManager.PasswordExceptionsList.decorate(
103 this.passwordExceptionsList_);
104 this.passwordExceptionsList_.autoExpands = true;
108 * Handles search query changes.
109 * @param {!Event} e The event object.
112 handleSearchQueryChange_: function(e) {
113 if (this.queryDelayTimerId_)
114 window.clearTimeout(this.queryDelayTimerId_);
116 // Searching cookies uses a timeout of 500ms. We use a shorter timeout
117 // because there are probably fewer passwords and we want the UI to be
118 // snappier since users will expect that it's "less work."
119 this.queryDelayTimerId_ = window.setTimeout(
120 this.searchPasswords_.bind(this), 250);
124 * Search passwords using text in |password-search-box|.
127 searchPasswords_: function() {
128 this.queryDelayTimerId_ = 0;
129 var filter = $('password-search-box').value;
130 filter = (filter == '') ? null : filter;
131 if (this.lastQuery_ != filter) {
132 this.lastQuery_ = filter;
133 // Searching for passwords has the side effect of requerying the
134 // underlying password store. This is done intentionally, as on OS X and
135 // Linux they can change from outside and we won't be notified of it.
136 chrome.send('updatePasswordLists');
141 * Updates the visibility of the list and empty list placeholder.
142 * @param {!cr.ui.List} list The list to toggle visilibility for.
144 updateListVisibility_: function(list) {
145 var empty = list.dataModel.length == 0;
146 var listPlaceHolderID = list.id + '-empty-placeholder';
148 $(listPlaceHolderID).hidden = !empty;
152 * Updates the data model for the saved passwords list with the values from
154 * @param {Array} entries The list of saved password data.
156 setSavedPasswordsList_: function(entries) {
157 if (this.lastQuery_) {
158 // Implement password searching here in javascript, rather than in C++.
159 // The number of saved passwords shouldn't be too big for us to handle.
160 var query = this.lastQuery_;
161 var filter = function(entry, index, list) {
162 // Search both URL and username.
163 if (entry[0].toLowerCase().indexOf(query.toLowerCase()) >= 0 ||
164 entry[1].toLowerCase().indexOf(query.toLowerCase()) >= 0) {
165 // Keep the original index so we can delete correctly. See also
166 // deleteItemAtIndex() in password_manager_list.js that uses this.
172 entries = entries.filter(filter);
174 this.savedPasswordsList_.dataModel = new ArrayDataModel(entries);
175 this.updateListVisibility_(this.savedPasswordsList_);
179 * Updates the data model for the password exceptions list with the values
181 * @param {!Array} entries The list of password exception data.
183 setPasswordExceptionsList_: function(entries) {
184 this.passwordExceptionsList_.dataModel = new ArrayDataModel(entries);
185 this.updateListVisibility_(this.passwordExceptionsList_);
189 * Reveals the password for a saved password entry. This is called by the
190 * backend after it has authenticated the user.
191 * @param {number} index The original index of the entry in the model.
192 * @param {string} password The saved password.
194 showPassword_: function(index, password) {
195 var model = this.savedPasswordsList_.dataModel;
196 if (this.lastQuery_) {
197 // When a filter is active, |index| does not represent the current
198 // index in the model, but each entry stores its original index, so
199 // we can find the item using a linear search.
200 for (var i = 0; i < model.length; ++i) {
201 if (model.item(i)[3] == index) {
208 // Reveal the password in the UI.
209 var item = this.savedPasswordsList_.getListItemByIndex(index);
210 item.showPassword(password);
215 * Removes a saved password.
216 * @param {number} rowIndex indicating the row to remove.
218 PasswordManager.removeSavedPassword = function(rowIndex) {
219 chrome.send('removeSavedPassword', [String(rowIndex)]);
223 * Removes a password exception.
224 * @param {number} rowIndex indicating the row to remove.
226 PasswordManager.removePasswordException = function(rowIndex) {
227 chrome.send('removePasswordException', [String(rowIndex)]);
230 PasswordManager.requestShowPassword = function(index) {
231 chrome.send('requestShowPassword', [index]);
234 // Forward public APIs to private implementations on the singleton instance.
235 cr.makePublic(PasswordManager, [
236 'setSavedPasswordsList',
237 'setPasswordExceptionsList',
243 PasswordManager: PasswordManager