Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(343)

Side by Side Diff: chrome/browser/resources/options/password_manager_list.js

Issue 489103004: Allow editing passwords in settings/passwords (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: It supports overwriting and adding. Added the unit tests. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698