password_manager_list.js revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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 5cr.define('options.passwordManager', function() { 6 /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel; 7 /** @const */ var DeletableItemList = options.DeletableItemList; 8 /** @const */ var DeletableItem = options.DeletableItem; 9 /** @const */ var List = cr.ui.List; 10 11 /** 12 * Creates a new passwords list item. 13 * @param {Array} entry An array of the form [url, username, password]. When 14 * the list has been filtered, a fourth element [index] may be present. 15 * @constructor 16 * @extends {cr.ui.ListItem} 17 */ 18 function PasswordListItem(entry, showPasswords) { 19 var el = cr.doc.createElement('div'); 20 el.dataItem = entry; 21 el.__proto__ = PasswordListItem.prototype; 22 el.decorate(showPasswords); 23 24 return el; 25 } 26 27 PasswordListItem.prototype = { 28 __proto__: DeletableItem.prototype, 29 30 /** @override */ 31 decorate: function(showPasswords) { 32 DeletableItem.prototype.decorate.call(this); 33 34 // The URL of the site. 35 var urlLabel = this.ownerDocument.createElement('div'); 36 urlLabel.classList.add('favicon-cell'); 37 urlLabel.classList.add('weakrtl'); 38 urlLabel.classList.add('url'); 39 urlLabel.setAttribute('title', this.url); 40 urlLabel.textContent = this.url; 41 42 // The favicon URL is prefixed with "origin/", which essentially removes 43 // the URL path past the top-level domain and ensures that a scheme (e.g., 44 // http) is being used. This ensures that the favicon returned is the 45 // default favicon for the domain and that the URL has a scheme if none 46 // is present in the password manager. 47 urlLabel.style.backgroundImage = getFaviconImageSet( 48 'origin/' + this.url, 16); 49 this.contentElement.appendChild(urlLabel); 50 51 // The stored username. 52 var usernameLabel = this.ownerDocument.createElement('div'); 53 usernameLabel.className = 'name'; 54 usernameLabel.textContent = this.username; 55 this.contentElement.appendChild(usernameLabel); 56 57 // The stored password. 58 var passwordInputDiv = this.ownerDocument.createElement('div'); 59 passwordInputDiv.className = 'password'; 60 61 // The password input field. 62 var passwordInput = this.ownerDocument.createElement('input'); 63 passwordInput.type = 'password'; 64 passwordInput.className = 'inactive-password'; 65 passwordInput.readOnly = true; 66 passwordInput.value = showPasswords ? this.password : '********'; 67 passwordInputDiv.appendChild(passwordInput); 68 69 // The show/hide button. 70 if (showPasswords) { 71 var button = this.ownerDocument.createElement('button'); 72 button.hidden = true; 73 button.className = 'list-inline-button custom-appearance'; 74 button.textContent = loadTimeData.getString('passwordShowButton'); 75 button.addEventListener('click', this.onClick_, true); 76 passwordInputDiv.appendChild(button); 77 } 78 79 this.contentElement.appendChild(passwordInputDiv); 80 }, 81 82 /** @override */ 83 selectionChanged: function() { 84 var passwordInput = this.querySelector('input[type=password]'); 85 var textInput = this.querySelector('input[type=text]'); 86 var input = passwordInput || textInput; 87 var button = input.nextSibling; 88 // |button| doesn't exist when passwords can't be shown. 89 if (!button) 90 return; 91 if (this.selected) { 92 input.classList.remove('inactive-password'); 93 button.hidden = false; 94 } else { 95 input.classList.add('inactive-password'); 96 button.hidden = true; 97 } 98 }, 99 100 /** 101 * On-click event handler. Swaps the type of the input field from password 102 * to text and back. 103 * @private 104 */ 105 onClick_: function(event) { 106 // The password is the input element previous to the button. 107 var button = event.currentTarget; 108 var passwordInput = button.previousSibling; 109 if (passwordInput.type == 'password') { 110 passwordInput.type = 'text'; 111 button.textContent = loadTimeData.getString('passwordHideButton'); 112 } else { 113 passwordInput.type = 'password'; 114 button.textContent = loadTimeData.getString('passwordShowButton'); 115 } 116 }, 117 118 /** 119 * Get and set the URL for the entry. 120 * @type {string} 121 */ 122 get url() { 123 return this.dataItem[0]; 124 }, 125 set url(url) { 126 this.dataItem[0] = url; 127 }, 128 129 /** 130 * Get and set the username for the entry. 131 * @type {string} 132 */ 133 get username() { 134 return this.dataItem[1]; 135 }, 136 set username(username) { 137 this.dataItem[1] = username; 138 }, 139 140 /** 141 * Get and set the password for the entry. 142 * @type {string} 143 */ 144 get password() { 145 return this.dataItem[2]; 146 }, 147 set password(password) { 148 this.dataItem[2] = password; 149 }, 150 }; 151 152 /** 153 * Creates a new PasswordExceptions list item. 154 * @param {Array} entry A pair of the form [url, username]. 155 * @constructor 156 * @extends {Deletable.ListItem} 157 */ 158 function PasswordExceptionsListItem(entry) { 159 var el = cr.doc.createElement('div'); 160 el.dataItem = entry; 161 el.__proto__ = PasswordExceptionsListItem.prototype; 162 el.decorate(); 163 164 return el; 165 } 166 167 PasswordExceptionsListItem.prototype = { 168 __proto__: DeletableItem.prototype, 169 170 /** 171 * Call when an element is decorated as a list item. 172 */ 173 decorate: function() { 174 DeletableItem.prototype.decorate.call(this); 175 176 // The URL of the site. 177 var urlLabel = this.ownerDocument.createElement('div'); 178 urlLabel.className = 'url'; 179 urlLabel.classList.add('favicon-cell'); 180 urlLabel.classList.add('weakrtl'); 181 urlLabel.textContent = this.url; 182 183 // The favicon URL is prefixed with "origin/", which essentially removes 184 // the URL path past the top-level domain and ensures that a scheme (e.g., 185 // http) is being used. This ensures that the favicon returned is the 186 // default favicon for the domain and that the URL has a scheme if none 187 // is present in the password manager. 188 urlLabel.style.backgroundImage = getFaviconImageSet( 189 'origin/' + this.url, 16); 190 this.contentElement.appendChild(urlLabel); 191 }, 192 193 /** 194 * Get the url for the entry. 195 * @type {string} 196 */ 197 get url() { 198 return this.dataItem; 199 }, 200 set url(url) { 201 this.dataItem = url; 202 }, 203 }; 204 205 /** 206 * Create a new passwords list. 207 * @constructor 208 * @extends {cr.ui.List} 209 */ 210 var PasswordsList = cr.ui.define('list'); 211 212 PasswordsList.prototype = { 213 __proto__: DeletableItemList.prototype, 214 215 /** 216 * Whether passwords can be revealed or not. 217 * @type {boolean} 218 * @private 219 */ 220 showPasswords_: true, 221 222 /** @override */ 223 decorate: function() { 224 DeletableItemList.prototype.decorate.call(this); 225 Preferences.getInstance().addEventListener( 226 'profile.password_manager_allow_show_passwords', 227 this.onPreferenceChanged_.bind(this)); 228 }, 229 230 /** 231 * Listener for changes on the preference. 232 * @param {Event} event The preference update event. 233 * @private 234 */ 235 onPreferenceChanged_: function(event) { 236 this.showPasswords_ = event.value.value; 237 this.redraw(); 238 }, 239 240 /** @override */ 241 createItem: function(entry) { 242 return new PasswordListItem(entry, this.showPasswords_); 243 }, 244 245 /** @override */ 246 deleteItemAtIndex: function(index) { 247 var item = this.dataModel.item(index); 248 if (item && item.length > 3) { 249 // The fourth element, if present, is the original index to delete. 250 index = item[3]; 251 } 252 PasswordManager.removeSavedPassword(index); 253 }, 254 255 /** 256 * The length of the list. 257 */ 258 get length() { 259 return this.dataModel.length; 260 }, 261 }; 262 263 /** 264 * Create a new passwords list. 265 * @constructor 266 * @extends {cr.ui.List} 267 */ 268 var PasswordExceptionsList = cr.ui.define('list'); 269 270 PasswordExceptionsList.prototype = { 271 __proto__: DeletableItemList.prototype, 272 273 /** @override */ 274 createItem: function(entry) { 275 return new PasswordExceptionsListItem(entry); 276 }, 277 278 /** @override */ 279 deleteItemAtIndex: function(index) { 280 PasswordManager.removePasswordException(index); 281 }, 282 283 /** 284 * The length of the list. 285 */ 286 get length() { 287 return this.dataModel.length; 288 }, 289 }; 290 291 return { 292 PasswordListItem: PasswordListItem, 293 PasswordExceptionsListItem: PasswordExceptionsListItem, 294 PasswordsList: PasswordsList, 295 PasswordExceptionsList: PasswordExceptionsList, 296 }; 297}); 298