OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 cr.define('options.passwordManager', function() { | 5 cr.define('options.passwordManager', function() { |
6 /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel; | 6 /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel; |
7 /** @const */ var DeletableItemList = options.DeletableItemList; | 7 /** @const */ var DeletableItemList = options.DeletableItemList; |
8 /** @const */ var DeletableItem = options.DeletableItem; | 8 /** @const */ var DeletableItem = options.DeletableItem; |
| 9 /** @const */ var InlineEditableItemList = options.InlineEditableItemList; |
| 10 /** @const */ var InlineEditableItem = options.InlineEditableItem; |
9 /** @const */ var List = cr.ui.List; | 11 /** @const */ var List = cr.ui.List; |
10 | 12 |
11 /** | 13 /** |
12 * Creates a new passwords list item. | 14 * Creates a new passwords list item. |
13 * @param {ArrayDataModel} dataModel The data model that contains this item. | 15 * @param {ArrayDataModel} dataModel The data model that contains this item. |
14 * @param {Array} entry An array of the form [url, username, password]. When | 16 * @param {Array} entry An array of the form [url, username, password]. When |
15 * the list has been filtered, a fourth element [index] may be present. | 17 * the list has been filtered, a fourth element [index] may be present. |
16 * @param {boolean} showPasswords If true, add a button to the element to | 18 * @param {boolean} showPasswords If true, add a button to the element to |
17 * allow the user to reveal the saved password. | 19 * allow the user to reveal the saved password. |
18 * @constructor | 20 * @constructor |
19 * @extends {cr.ui.ListItem} | 21 * @extends {options.InlineEditableItem} |
20 */ | 22 */ |
21 function PasswordListItem(dataModel, entry, showPasswords) { | 23 function PasswordListItem(dataModel, entry, showPasswords) { |
22 var el = cr.doc.createElement('div'); | 24 var el = cr.doc.createElement('div'); |
23 el.dataItem = entry; | 25 el.dataItem = entry; |
24 el.dataModel = dataModel; | 26 el.dataModel = dataModel; |
25 el.__proto__ = PasswordListItem.prototype; | 27 el.__proto__ = PasswordListItem.prototype; |
26 el.decorate(showPasswords); | 28 el.decorate(showPasswords); |
27 | 29 |
28 return el; | 30 return el; |
29 } | 31 } |
30 | 32 |
31 PasswordListItem.prototype = { | 33 PasswordListItem.prototype = { |
32 __proto__: DeletableItem.prototype, | 34 __proto__: InlineEditableItem.prototype, |
33 | 35 |
34 /** @override */ | 36 /** @override */ |
35 decorate: function(showPasswords) { | 37 decorate: function(showPasswords) { |
36 DeletableItem.prototype.decorate.call(this); | 38 InlineEditableItem.prototype.decorate.call(this); |
| 39 |
| 40 this.isPlaceholder = !this.url; |
37 | 41 |
38 // The URL of the site. | 42 // The URL of the site. |
39 var urlLabel = this.ownerDocument.createElement('div'); | 43 this.contentElement.appendChild(this.setupUrlElement()); |
40 urlLabel.classList.add('favicon-cell'); | 44 |
41 urlLabel.classList.add('weakrtl'); | 45 // The username. |
42 urlLabel.classList.add('url'); | 46 this.contentElement.appendChild(this.setupUsernameElement()); |
43 urlLabel.setAttribute('title', this.url); | 47 |
44 urlLabel.textContent = this.url; | 48 // The password. |
45 | |
46 // The favicon URL is prefixed with "origin/", which essentially removes | |
47 // the URL path past the top-level domain and ensures that a scheme (e.g., | |
48 // http) is being used. This ensures that the favicon returned is the | |
49 // default favicon for the domain and that the URL has a scheme if none | |
50 // is present in the password manager. | |
51 urlLabel.style.backgroundImage = getFaviconImageSet( | |
52 'origin/' + this.url, 16); | |
53 this.contentElement.appendChild(urlLabel); | |
54 | |
55 // The stored username. | |
56 var usernameLabel = this.ownerDocument.createElement('div'); | |
57 usernameLabel.className = 'name'; | |
58 usernameLabel.textContent = this.username; | |
59 usernameLabel.title = this.username; | |
60 this.contentElement.appendChild(usernameLabel); | |
61 | |
62 // The stored password. | |
63 var passwordInputDiv = this.ownerDocument.createElement('div'); | 49 var passwordInputDiv = this.ownerDocument.createElement('div'); |
64 passwordInputDiv.className = 'password'; | 50 passwordInputDiv.className = 'password'; |
65 | 51 |
66 // The password input field. | 52 // The password input field. |
67 var passwordInput = this.ownerDocument.createElement('input'); | 53 var passwordInput = this.ownerDocument.createElement('input'); |
68 passwordInput.type = 'password'; | 54 passwordInput.type = 'password'; |
69 passwordInput.className = 'inactive-password'; | 55 if (!this.isPlaceholder) { |
70 passwordInput.readOnly = true; | 56 passwordInput.className = 'inactive-password'; |
71 passwordInput.value = showPasswords ? this.password : '********'; | 57 passwordInput.readOnly = true; |
| 58 passwordInput.value = showPasswords ? this.password : '********'; |
| 59 } |
| 60 this.passwordField = passwordInput; |
| 61 |
| 62 // Makes the password input field editable. |
| 63 this.addEditField(passwordInput, null); |
| 64 |
| 65 // Keeps the password validity updated. |
| 66 this.updatePasswordValidity(); |
| 67 var thisListItem = this; |
| 68 passwordInput.addEventListener('input', function(event) { |
| 69 thisListItem.updatePasswordValidity(); |
| 70 }); |
| 71 |
72 passwordInputDiv.appendChild(passwordInput); | 72 passwordInputDiv.appendChild(passwordInput); |
73 this.passwordField = passwordInput; | 73 |
74 | 74 // The list-inline buttons. |
75 // The show/hide button. | 75 if (!this.isPlaceholder) { |
76 if (showPasswords) { | 76 // The container of the list-inline buttons. |
77 var button = this.ownerDocument.createElement('button'); | 77 var buttonsContainer = this.ownerDocument.createElement('div'); |
78 button.hidden = true; | 78 buttonsContainer.className = 'list-inline-buttons-container'; |
79 button.className = 'list-inline-button custom-appearance'; | 79 |
80 button.textContent = loadTimeData.getString('passwordShowButton'); | 80 var mousedownEventHandler = function(event) { |
81 button.addEventListener('click', this.onClick_.bind(this), true); | |
82 button.addEventListener('mousedown', function(event) { | |
83 // Don't focus on this button by mousedown. | 81 // Don't focus on this button by mousedown. |
84 event.preventDefault(); | 82 event.preventDefault(); |
85 // Don't handle list item selection. It causes focus change. | 83 // Don't handle list item selection. It causes focus change. |
86 event.stopPropagation(); | 84 event.stopPropagation(); |
87 }, false); | 85 }; |
88 passwordInputDiv.appendChild(button); | 86 |
89 this.passwordShowButton = button; | 87 // The overwrite button. |
| 88 var overwriteButton = this.ownerDocument.createElement('button'); |
| 89 overwriteButton.className = |
| 90 'list-inline-button custom-appearance overwrite-button'; |
| 91 overwriteButton.textContent = loadTimeData.getString( |
| 92 'passwordOverwriteButton'); |
| 93 overwriteButton.addEventListener( |
| 94 'click', this.onClickOverwriteButton_.bind(this), true); |
| 95 overwriteButton.addEventListener( |
| 96 'mousedown', mousedownEventHandler, false); |
| 97 buttonsContainer.appendChild(overwriteButton); |
| 98 this.passwordOverwriteButton = overwriteButton; |
| 99 |
| 100 // The show/hide button. |
| 101 if (showPasswords) { |
| 102 var button = this.ownerDocument.createElement('button'); |
| 103 button.className = 'list-inline-button custom-appearance'; |
| 104 button.textContent = loadTimeData.getString('passwordShowButton'); |
| 105 button.addEventListener( |
| 106 'click', this.onClickShowButton_.bind(this), true); |
| 107 button.addEventListener('mousedown', mousedownEventHandler, false); |
| 108 buttonsContainer.appendChild(button); |
| 109 this.passwordShowButton = button; |
| 110 } |
| 111 |
| 112 passwordInputDiv.appendChild(buttonsContainer); |
90 } | 113 } |
91 | 114 |
92 this.contentElement.appendChild(passwordInputDiv); | 115 this.contentElement.appendChild(passwordInputDiv); |
| 116 |
| 117 // Adds the event listeners for editing. |
| 118 this.addEventListener('canceledit', this.onEditCancelled_); |
| 119 this.addEventListener('commitedit', this.onEditCommitted_); |
| 120 }, |
| 121 |
| 122 /** |
| 123 * Constructs and returns the URL element for this item. |
| 124 * @return {HTMLElement} The URL element. |
| 125 */ |
| 126 setupUrlElement: function() { |
| 127 var urlEl = this.ownerDocument.createElement('div'); |
| 128 urlEl.classList.add('favicon-cell'); |
| 129 urlEl.classList.add('weakrtl'); |
| 130 urlEl.classList.add('url'); |
| 131 urlEl.setAttribute('title', this.url); |
| 132 urlEl.textContent = this.url; |
| 133 |
| 134 // The favicon URL is prefixed with "origin/", which essentially removes |
| 135 // the URL path past the top-level domain and ensures that a scheme (e.g., |
| 136 // http) is being used. This ensures that the favicon returned is the |
| 137 // default favicon for the domain and that the URL has a scheme if none is |
| 138 // present in the password manager. |
| 139 urlEl.style.backgroundImage = getFaviconImageSet( |
| 140 'origin/' + this.url, 16); |
| 141 return urlEl; |
| 142 }, |
| 143 |
| 144 /** |
| 145 * Constructs and returns the username element for this item. |
| 146 * @return {HTMLElement} The username element. |
| 147 */ |
| 148 setupUsernameElement: function() { |
| 149 var usernameEl = this.ownerDocument.createElement('div'); |
| 150 usernameEl.className = 'name'; |
| 151 usernameEl.textContent = this.username; |
| 152 usernameEl.title = this.username; |
| 153 return usernameEl; |
93 }, | 154 }, |
94 | 155 |
95 /** @override */ | 156 /** @override */ |
96 selectionChanged: function() { | 157 selectionChanged: function() { |
| 158 InlineEditableItem.prototype.selectionChanged.call(this); |
| 159 |
| 160 // Don't set 'inactive-password' class for the placeholder so that it |
| 161 // shows the background and the borders. |
| 162 if (this.isPlaceholder) |
| 163 return; |
| 164 |
97 var input = this.passwordField; | 165 var input = this.passwordField; |
98 var button = this.passwordShowButton; | |
99 // The button doesn't exist when passwords can't be shown. | |
100 if (!button) | |
101 return; | |
102 | |
103 if (this.selected) { | 166 if (this.selected) { |
104 input.classList.remove('inactive-password'); | 167 input.classList.remove('inactive-password'); |
105 button.hidden = false; | |
106 } else { | 168 } else { |
107 input.classList.add('inactive-password'); | 169 input.classList.add('inactive-password'); |
108 button.hidden = true; | |
109 } | 170 } |
110 }, | 171 }, |
111 | 172 |
112 /** | 173 /** @override */ |
113 * Reveals the plain text password of this entry. | 174 get currentInputIsValid() { |
| 175 return !!this.passwordField.value; |
| 176 }, |
| 177 |
| 178 /** |
| 179 * Returns if the password has been edited. |
| 180 * @return {boolean} Whether the password has been edited. |
| 181 */ |
| 182 passwordHasBeenEdited: function() { |
| 183 return this.passwordField.value != this.password || this.overwriting; |
| 184 }, |
| 185 |
| 186 /** @override */ |
| 187 get hasBeenEdited() { |
| 188 return this.passwordHasBeenEdited(); |
| 189 }, |
| 190 |
| 191 /** |
| 192 * Reveals the plain text password of this entry. Never called for the Add |
| 193 * New Entry row. |
| 194 * @param {string} password The plain text password. |
114 */ | 195 */ |
115 showPassword: function(password) { | 196 showPassword: function(password) { |
116 this.passwordField.value = password; | 197 this.overwriting = false; |
| 198 this.password = password; |
| 199 this.setPasswordFieldValue_(password); |
117 this.passwordField.type = 'text'; | 200 this.passwordField.type = 'text'; |
118 | 201 this.passwordField.readOnly = false; |
| 202 |
| 203 this.passwordOverwriteButton.hidden = true; |
119 var button = this.passwordShowButton; | 204 var button = this.passwordShowButton; |
120 if (button) | 205 if (button) |
121 button.textContent = loadTimeData.getString('passwordHideButton'); | 206 button.textContent = loadTimeData.getString('passwordHideButton'); |
122 }, | 207 }, |
123 | 208 |
124 /** | 209 /** |
125 * Hides the plain text password of this entry. | 210 * Hides the plain text password of this entry. Never called for the Add |
| 211 * New Entry row. |
126 */ | 212 */ |
127 hidePassword: function() { | 213 hidePassword: function() { |
128 this.passwordField.type = 'password'; | 214 this.passwordField.type = 'password'; |
129 | 215 this.passwordField.readOnly = true; |
| 216 |
| 217 this.passwordOverwriteButton.hidden = false; |
130 var button = this.passwordShowButton; | 218 var button = this.passwordShowButton; |
131 if (button) | 219 if (button) |
132 button.textContent = loadTimeData.getString('passwordShowButton'); | 220 button.textContent = loadTimeData.getString('passwordShowButton'); |
133 }, | 221 }, |
134 | 222 |
135 /** | 223 /** |
| 224 * Resets the input fields to their original values and states. |
| 225 */ |
| 226 resetInputs: function() { |
| 227 this.finishOverwriting_(); |
| 228 this.setPasswordFieldValue_(this.password); |
| 229 }, |
| 230 |
| 231 /** |
| 232 * Commits the new data to the browser. |
| 233 */ |
| 234 finishEdit: function() { |
| 235 this.password = this.passwordField.value; |
| 236 this.finishOverwriting_(); |
| 237 PasswordManager.updatePassword( |
| 238 this.getOriginalIndex_(), this.passwordField.value); |
| 239 }, |
| 240 |
| 241 /** |
| 242 * Called with the response of the browser, which indicates the validity of |
| 243 * the URL. |
| 244 * @param {string} url The URL. |
| 245 * @param {boolean} valid The validity of the URL. |
| 246 */ |
| 247 originValidityCheckComplete: function(url, valid) { |
| 248 // Does nothing here. |
| 249 }, |
| 250 |
| 251 /** |
| 252 * Updates the custom validity of the password input field. |
| 253 */ |
| 254 updatePasswordValidity: function() { |
| 255 this.passwordField.setCustomValidity(this.passwordField.value ? '' : ' '); |
| 256 }, |
| 257 |
| 258 /** |
| 259 * Finishes password overwriting. |
| 260 * @private |
| 261 */ |
| 262 finishOverwriting_: function() { |
| 263 if (!this.overwriting) |
| 264 return; |
| 265 this.overwriting = false; |
| 266 this.passwordOverwriteButton.hidden = false; |
| 267 this.passwordField.readOnly = true; |
| 268 }, |
| 269 |
| 270 /** |
| 271 * Sets the value of the password input field. |
| 272 * @param {string} password The new value. |
| 273 * @private |
| 274 */ |
| 275 setPasswordFieldValue_: function(password) { |
| 276 this.passwordField.value = password; |
| 277 this.updatePasswordValidity(); |
| 278 }, |
| 279 |
| 280 /** |
136 * Get the original index of this item in the data model. | 281 * Get the original index of this item in the data model. |
137 * @return {number} The index. | 282 * @return {number} The index. |
138 * @private | 283 * @private |
139 */ | 284 */ |
140 getOriginalIndex_: function() { | 285 getOriginalIndex_: function() { |
141 var index = this.dataItem[3]; | 286 var index = this.dataItem[3]; |
142 return index ? index : this.dataModel.indexOf(this.dataItem); | 287 return index ? index : this.dataModel.indexOf(this.dataItem); |
143 }, | 288 }, |
144 | 289 |
145 /** | 290 /** |
| 291 * Called when clicking the overwrite button. Allows the user to overwrite |
| 292 * the hidden password. |
| 293 * @param {Event} event The click event. |
| 294 * @private |
| 295 */ |
| 296 onClickOverwriteButton_: function(event) { |
| 297 this.overwriting = true; |
| 298 this.passwordOverwriteButton.hidden = true; |
| 299 |
| 300 this.setPasswordFieldValue_(''); |
| 301 this.passwordField.readOnly = false; |
| 302 this.passwordField.focus(); |
| 303 }, |
| 304 |
| 305 /** |
146 * On-click event handler. Swaps the type of the input field from password | 306 * On-click event handler. Swaps the type of the input field from password |
147 * to text and back. | 307 * to text and back. |
148 * @private | 308 * @private |
149 */ | 309 */ |
150 onClick_: function(event) { | 310 onClickShowButton_: function(event) { |
| 311 // Prevents committing an edit. |
| 312 this.resetInputs(); |
| 313 |
151 if (this.passwordField.type == 'password') { | 314 if (this.passwordField.type == 'password') { |
152 // After the user is authenticated, showPassword() will be called. | 315 // After the user is authenticated, showPassword() will be called. |
153 PasswordManager.requestShowPassword(this.getOriginalIndex_()); | 316 PasswordManager.requestShowPassword(this.getOriginalIndex_()); |
154 } else { | 317 } else { |
155 this.hidePassword(); | 318 this.hidePassword(); |
156 } | 319 } |
157 }, | 320 }, |
158 | 321 |
159 /** | 322 /** |
| 323 * Called when cancelling an edit. |
| 324 * @param {Event} event The canceledit event. |
| 325 * @private |
| 326 */ |
| 327 onEditCancelled_: function(event) { |
| 328 this.resetInputs(); |
| 329 }, |
| 330 |
| 331 /** |
| 332 * Called when committing an edit. |
| 333 * @param {Event} event The commitedit event. |
| 334 * @private |
| 335 */ |
| 336 onEditCommitted_: function(event) { |
| 337 this.finishEdit(); |
| 338 }, |
| 339 |
| 340 /** |
160 * Get and set the URL for the entry. | 341 * Get and set the URL for the entry. |
161 * @type {string} | 342 * @type {string} |
162 */ | 343 */ |
163 get url() { | 344 get url() { |
164 return this.dataItem[0]; | 345 var url = this.dataItem[0]; |
| 346 return url ? url : ''; |
165 }, | 347 }, |
166 set url(url) { | 348 set url(url) { |
167 this.dataItem[0] = url; | 349 this.dataItem[0] = url; |
168 }, | 350 }, |
169 | 351 |
170 /** | 352 /** |
171 * Get and set the username for the entry. | 353 * Get and set the username for the entry. |
172 * @type {string} | 354 * @type {string} |
173 */ | 355 */ |
174 get username() { | 356 get username() { |
175 return this.dataItem[1]; | 357 var username = this.dataItem[1]; |
| 358 return username ? username : ''; |
176 }, | 359 }, |
177 set username(username) { | 360 set username(username) { |
178 this.dataItem[1] = username; | 361 this.dataItem[1] = username; |
179 }, | 362 }, |
180 | 363 |
181 /** | 364 /** |
182 * Get and set the password for the entry. | 365 * Get and set the password for the entry. |
183 * @type {string} | 366 * @type {string} |
184 */ | 367 */ |
185 get password() { | 368 get password() { |
186 return this.dataItem[2]; | 369 var password = this.dataItem[2]; |
| 370 return password ? password : ''; |
187 }, | 371 }, |
188 set password(password) { | 372 set password(password) { |
189 this.dataItem[2] = password; | 373 this.dataItem[2] = password; |
190 }, | 374 }, |
191 }; | 375 }; |
192 | 376 |
193 /** | 377 /** |
| 378 * Creates a new passwords list item for the Add New Entry row. |
| 379 * @param {ArrayDataModel} dataModel The data model that contains this item. |
| 380 * @param {boolean} showPasswords Kept for the consistency. |
| 381 * @constructor |
| 382 * @extends {options.passwordManager.PasswordListItem} |
| 383 */ |
| 384 function PasswordAddRowListItem(dataModel, showPasswords) { |
| 385 var el = cr.doc.createElement('div'); |
| 386 el.dataItem = []; |
| 387 el.dataModel = dataModel; |
| 388 el.__proto__ = PasswordAddRowListItem.prototype; |
| 389 el.decorate(showPasswords); |
| 390 |
| 391 return el; |
| 392 } |
| 393 |
| 394 PasswordAddRowListItem.prototype = { |
| 395 __proto__: PasswordListItem.prototype, |
| 396 |
| 397 /** @override */ |
| 398 decorate: function(showPasswords) { |
| 399 PasswordListItem.prototype.decorate.call(this, showPasswords); |
| 400 |
| 401 this.urlField.placeholder = loadTimeData.getString( |
| 402 'newPasswordUrlFieldPlaceholder'); |
| 403 this.usernameField.placeholder = loadTimeData.getString( |
| 404 'newPasswordUsernameFieldPlaceholder'); |
| 405 this.passwordField.placeholder = loadTimeData.getString( |
| 406 'newPasswordPasswordFieldPlaceholder'); |
| 407 |
| 408 // Sets the validity of the URL initially. |
| 409 this.setUrlValid_(false); |
| 410 }, |
| 411 |
| 412 /** @override */ |
| 413 setupUrlElement: function() { |
| 414 var urlEl = this.createEditableTextCell(''); |
| 415 urlEl.classList.add('favicon-cell'); |
| 416 urlEl.classList.add('weakrtl'); |
| 417 urlEl.classList.add('url'); |
| 418 |
| 419 var urlField = urlEl.querySelector('input'); |
| 420 urlField.addEventListener('input', this.onUrlInput_.bind(this)); |
| 421 this.urlField = urlField; |
| 422 |
| 423 return urlEl; |
| 424 }, |
| 425 |
| 426 /** @override */ |
| 427 setupUsernameElement: function() { |
| 428 var usernameEl = this.createEditableTextCell(''); |
| 429 usernameEl.className = 'name'; |
| 430 |
| 431 this.usernameField = usernameEl.querySelector('input'); |
| 432 |
| 433 return usernameEl; |
| 434 }, |
| 435 |
| 436 /** @override */ |
| 437 get currentInputIsValid() { |
| 438 return this.urlValidityKnown && this.urlIsValid && |
| 439 this.passwordField.value; |
| 440 }, |
| 441 |
| 442 /** @override */ |
| 443 get hasBeenEdited() { |
| 444 return this.urlField.value || this.usernameField.value || |
| 445 this.passwordHasBeenEdited(); |
| 446 }, |
| 447 |
| 448 /** @override */ |
| 449 resetInputs: function() { |
| 450 PasswordListItem.prototype.resetInputs.call(this); |
| 451 |
| 452 this.urlField.value = ''; |
| 453 this.usernameField.value = ''; |
| 454 |
| 455 this.setUrlValid_(false); |
| 456 }, |
| 457 |
| 458 /** @override */ |
| 459 finishEdit: function() { |
| 460 var newUrl = this.urlField.value; |
| 461 var newUsername = this.usernameField.value; |
| 462 var newPassword = this.passwordField.value; |
| 463 this.resetInputs(); |
| 464 |
| 465 PasswordManager.addPassword(newUrl, newUsername, newPassword); |
| 466 }, |
| 467 |
| 468 /** @override */ |
| 469 originValidityCheckComplete: function(url, valid) { |
| 470 if (url == this.urlField.value) |
| 471 this.setUrlValid_(valid); |
| 472 }, |
| 473 |
| 474 /** |
| 475 * Updates whether the URL in the input is valid. |
| 476 * @param {boolean} valid The validity of the URL. |
| 477 * @private |
| 478 */ |
| 479 setUrlValid_: function(valid) { |
| 480 this.urlIsValid = valid; |
| 481 this.urlValidityKnown = true; |
| 482 if (this.urlField) |
| 483 this.urlField.setCustomValidity(valid ? '' : ' '); |
| 484 }, |
| 485 |
| 486 /** |
| 487 * Called when inputting to a URL input. |
| 488 * @param {Event} event The input event. |
| 489 * @private |
| 490 */ |
| 491 onUrlInput_: function(event) { |
| 492 this.urlValidityKnown = false; |
| 493 PasswordManager.checkOriginValidityForAdding(this.urlField.value); |
| 494 }, |
| 495 }; |
| 496 |
| 497 /** |
194 * Creates a new PasswordExceptions list item. | 498 * Creates a new PasswordExceptions list item. |
195 * @param {Array} entry A pair of the form [url, username]. | 499 * @param {Array} entry A pair of the form [url, username]. |
196 * @constructor | 500 * @constructor |
197 * @extends {Deletable.ListItem} | 501 * @extends {Deletable.ListItem} |
198 */ | 502 */ |
199 function PasswordExceptionsListItem(entry) { | 503 function PasswordExceptionsListItem(entry) { |
200 var el = cr.doc.createElement('div'); | 504 var el = cr.doc.createElement('div'); |
201 el.dataItem = entry; | 505 el.dataItem = entry; |
202 el.__proto__ = PasswordExceptionsListItem.prototype; | 506 el.__proto__ = PasswordExceptionsListItem.prototype; |
203 el.decorate(); | 507 el.decorate(); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 return this.dataItem; | 543 return this.dataItem; |
240 }, | 544 }, |
241 set url(url) { | 545 set url(url) { |
242 this.dataItem = url; | 546 this.dataItem = url; |
243 }, | 547 }, |
244 }; | 548 }; |
245 | 549 |
246 /** | 550 /** |
247 * Create a new passwords list. | 551 * Create a new passwords list. |
248 * @constructor | 552 * @constructor |
249 * @extends {cr.ui.List} | 553 * @extends {options.InlineEditableItemList} |
250 */ | 554 */ |
251 var PasswordsList = cr.ui.define('list'); | 555 var PasswordsList = cr.ui.define('list'); |
252 | 556 |
253 PasswordsList.prototype = { | 557 PasswordsList.prototype = { |
254 __proto__: DeletableItemList.prototype, | 558 __proto__: InlineEditableItemList.prototype, |
255 | 559 |
256 /** | 560 /** |
257 * Whether passwords can be revealed or not. | 561 * Whether passwords can be revealed or not. |
258 * @type {boolean} | 562 * @type {boolean} |
259 * @private | 563 * @private |
260 */ | 564 */ |
261 showPasswords_: true, | 565 showPasswords_: true, |
262 | 566 |
263 /** @override */ | 567 /** @override */ |
264 decorate: function() { | 568 decorate: function() { |
265 DeletableItemList.prototype.decorate.call(this); | 569 InlineEditableItemList.prototype.decorate.call(this); |
266 Preferences.getInstance().addEventListener( | 570 Preferences.getInstance().addEventListener( |
267 'profile.password_manager_allow_show_passwords', | 571 'profile.password_manager_allow_show_passwords', |
268 this.onPreferenceChanged_.bind(this)); | 572 this.onPreferenceChanged_.bind(this)); |
269 }, | 573 }, |
270 | 574 |
271 /** | 575 /** |
272 * Listener for changes on the preference. | 576 * Listener for changes on the preference. |
273 * @param {Event} event The preference update event. | 577 * @param {Event} event The preference update event. |
274 * @private | 578 * @private |
275 */ | 579 */ |
276 onPreferenceChanged_: function(event) { | 580 onPreferenceChanged_: function(event) { |
277 this.showPasswords_ = event.value.value; | 581 this.showPasswords_ = event.value.value; |
278 this.redraw(); | 582 this.redraw(); |
279 }, | 583 }, |
280 | 584 |
281 /** @override */ | 585 /** @override */ |
282 createItem: function(entry) { | 586 createItem: function(entry) { |
283 var showPasswords = this.showPasswords_; | 587 var showPasswords = this.showPasswords_; |
284 | 588 |
285 if (loadTimeData.getBoolean('disableShowPasswords')) | 589 if (loadTimeData.getBoolean('disableShowPasswords')) |
286 showPasswords = false; | 590 showPasswords = false; |
287 | 591 |
288 return new PasswordListItem(this.dataModel, entry, showPasswords); | 592 if (entry) |
| 593 return new PasswordListItem(this.dataModel, entry, showPasswords); |
| 594 |
| 595 return new PasswordAddRowListItem(this.dataModel, showPasswords); |
289 }, | 596 }, |
290 | 597 |
291 /** @override */ | 598 /** @override */ |
292 deleteItemAtIndex: function(index) { | 599 deleteItemAtIndex: function(index) { |
293 var item = this.dataModel.item(index); | 600 var item = this.dataModel.item(index); |
294 if (item && item.length > 3) { | 601 if (item && item.length > 3) { |
295 // The fourth element, if present, is the original index to delete. | 602 // The fourth element, if present, is the original index to delete. |
296 index = item[3]; | 603 index = item[3]; |
297 } | 604 } |
298 PasswordManager.removeSavedPassword(index); | 605 PasswordManager.removeSavedPassword(index); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
334 }, | 641 }, |
335 }; | 642 }; |
336 | 643 |
337 return { | 644 return { |
338 PasswordListItem: PasswordListItem, | 645 PasswordListItem: PasswordListItem, |
339 PasswordExceptionsListItem: PasswordExceptionsListItem, | 646 PasswordExceptionsListItem: PasswordExceptionsListItem, |
340 PasswordsList: PasswordsList, | 647 PasswordsList: PasswordsList, |
341 PasswordExceptionsList: PasswordExceptionsList, | 648 PasswordExceptionsList: PasswordExceptionsList, |
342 }; | 649 }; |
343 }); | 650 }); |
OLD | NEW |