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