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. 4 5 cr.define('options', function() { 6 /** @const */ var OptionsPage = options.OptionsPage; 7 /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel; 8 9 ///////////////////////////////////////////////////////////////////////////// 10 // PasswordManager class: 11 12 /** 13 * Encapsulated handling of password and exceptions page. 14 * @constructor 15 */ 16 function PasswordManager() { 17 this.activeNavTab = null; 18 OptionsPage.call(this, 19 'passwords', 20 loadTimeData.getString('passwordsPageTabTitle'), 21 'password-manager'); 22 } 23 24 cr.addSingletonGetter(PasswordManager); 25 26 PasswordManager.prototype = { 27 __proto__: OptionsPage.prototype, 28 29 /** 30 * The saved passwords list. 31 * @type {DeletableItemList} 32 * @private 33 */ 34 savedPasswordsList_: null, 35 36 /** 37 * The password exceptions list. 38 * @type {DeletableItemList} 39 * @private 40 */ 41 passwordExceptionsList_: null, 42 43 /** 44 * The timer id of the timer set on search query change events. 45 * @type {number} 46 * @private 47 */ 48 queryDelayTimerId_: 0, 49 50 /** 51 * The most recent search query, or null if the query is empty. 52 * @type {?string} 53 * @private 54 */ 55 lastQuery_: null, 56 57 /** @override */ 58 initializePage: function() { 59 OptionsPage.prototype.initializePage.call(this); 60 61 $('password-manager-confirm').onclick = function() { 62 OptionsPage.closeOverlay(); 63 }; 64 65 $('password-search-box').addEventListener('search', 66 this.handleSearchQueryChange_.bind(this)); 67 68 this.createSavedPasswordsList_(); 69 this.createPasswordExceptionsList_(); 70 }, 71 72 /** @override */ 73 canShowPage: function() { 74 return !(cr.isChromeOS && UIAccountTweaks.loggedInAsGuest()); 75 }, 76 77 /** @override */ 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(); 83 }, 84 85 /** 86 * Creates, decorates and initializes the saved passwords list. 87 * @private 88 */ 89 createSavedPasswordsList_: function() { 90 this.savedPasswordsList_ = $('saved-passwords-list'); 91 options.passwordManager.PasswordsList.decorate(this.savedPasswordsList_); 92 this.savedPasswordsList_.autoExpands = true; 93 }, 94 95 /** 96 * Creates, decorates and initializes the password exceptions list. 97 * @private 98 */ 99 createPasswordExceptionsList_: function() { 100 this.passwordExceptionsList_ = $('password-exceptions-list'); 101 options.passwordManager.PasswordExceptionsList.decorate( 102 this.passwordExceptionsList_); 103 this.passwordExceptionsList_.autoExpands = true; 104 }, 105 106 /** 107 * Handles search query changes. 108 * @param {!Event} e The event object. 109 * @private 110 */ 111 handleSearchQueryChange_: function(e) { 112 if (this.queryDelayTimerId_) 113 window.clearTimeout(this.queryDelayTimerId_); 114 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); 120 }, 121 122 /** 123 * Search passwords using text in |password-search-box|. 124 * @private 125 */ 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'); 136 } 137 }, 138 139 /** 140 * Updates the visibility of the list and empty list placeholder. 141 * @param {!List} list The list to toggle visilibility for. 142 */ 143 updateListVisibility_: function(list) { 144 var empty = list.dataModel.length == 0; 145 var listPlaceHolderID = list.id + '-empty-placeholder'; 146 list.hidden = empty; 147 $(listPlaceHolderID).hidden = !empty; 148 }, 149 150 /** 151 * Updates the data model for the saved passwords list with the values from 152 * |entries|. 153 * @param {Array} entries The list of saved password data. 154 */ 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].indexOf(query) >= 0 || entry[1].indexOf(query) >= 0) { 163 // Keep the original index so we can delete correctly. See also 164 // deleteItemAtIndex() in password_manager_list.js that uses this. 165 entry[3] = index; 166 return true; 167 } 168 return false; 169 }; 170 entries = entries.filter(filter); 171 } 172 this.savedPasswordsList_.dataModel = new ArrayDataModel(entries); 173 this.updateListVisibility_(this.savedPasswordsList_); 174 }, 175 176 /** 177 * Updates the data model for the password exceptions list with the values 178 * from |entries|. 179 * @param {Array} entries The list of password exception data. 180 */ 181 setPasswordExceptionsList_: function(entries) { 182 this.passwordExceptionsList_.dataModel = new ArrayDataModel(entries); 183 this.updateListVisibility_(this.passwordExceptionsList_); 184 }, 185 }; 186 187 /** 188 * Removes a saved password. 189 * @param {number} rowIndex indicating the row to remove. 190 */ 191 PasswordManager.removeSavedPassword = function(rowIndex) { 192 chrome.send('removeSavedPassword', [String(rowIndex)]); 193 }; 194 195 /** 196 * Removes a password exception. 197 * @param {number} rowIndex indicating the row to remove. 198 */ 199 PasswordManager.removePasswordException = function(rowIndex) { 200 chrome.send('removePasswordException', [String(rowIndex)]); 201 }; 202 203 /** 204 * Removes all saved passwords. 205 */ 206 PasswordManager.removeAllPasswords = function() { 207 chrome.send('removeAllSavedPasswords'); 208 }; 209 210 /** 211 * Removes all password exceptions. 212 */ 213 PasswordManager.removeAllPasswordExceptions = function() { 214 chrome.send('removeAllPasswordExceptions'); 215 }; 216 217 PasswordManager.setSavedPasswordsList = function(entries) { 218 PasswordManager.getInstance().setSavedPasswordsList_(entries); 219 }; 220 221 PasswordManager.setPasswordExceptionsList = function(entries) { 222 PasswordManager.getInstance().setPasswordExceptionsList_(entries); 223 }; 224 225 // Export 226 return { 227 PasswordManager: PasswordManager 228 }; 229 230 }); 231