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.
5 cr
.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
;
11 /** @const */ var URL_DATA_INDEX
= 0;
12 /** @const */ var USERNAME_DATA_INDEX
= 1;
13 /** @const */ var PASSWORD_DATA_INDEX
= 2;
14 /** @const */ var FEDERATION_DATA_INDEX
= 3;
15 /** @const */ var ORIGINAL_DATA_INDEX
= 4;
18 * Creates a new passwords list item.
19 * @param {cr.ui.ArrayDataModel} dataModel The data model that contains this
21 * @param {Array} entry An array of the form [url, username, password,
22 * federation]. When the list has been filtered, a fifth element [index]
24 * @param {boolean} showPasswords If true, add a button to the element to
25 * allow the user to reveal the saved password.
27 * @extends {options.DeletableItem}
29 function PasswordListItem(dataModel
, entry
, showPasswords
) {
30 var el
= cr
.doc
.createElement('div');
32 el
.dataModel
= dataModel
;
33 el
.__proto__
= PasswordListItem
.prototype;
34 el
.showPasswords_
= showPasswords
;
40 PasswordListItem
.prototype = {
41 __proto__
: DeletableItem
.prototype,
44 decorate: function() {
45 DeletableItem
.prototype.decorate
.call(this);
47 // The URL of the site.
48 var urlLabel
= this.ownerDocument
.createElement('div');
49 urlLabel
.classList
.add('favicon-cell');
50 urlLabel
.classList
.add('weakrtl');
51 urlLabel
.classList
.add('url');
52 urlLabel
.setAttribute('title', this.url
);
53 urlLabel
.textContent
= this.url
;
55 // The favicon URL is prefixed with "origin/", which essentially removes
56 // the URL path past the top-level domain and ensures that a scheme (e.g.,
57 // http) is being used. This ensures that the favicon returned is the
58 // default favicon for the domain and that the URL has a scheme if none
59 // is present in the password manager.
60 urlLabel
.style
.backgroundImage
= getFaviconImageSet(
61 'origin/' + this.url
, 16);
62 this.contentElement
.appendChild(urlLabel
);
64 // The stored username.
65 var usernameLabel
= this.ownerDocument
.createElement('div');
66 usernameLabel
.className
= 'name';
67 usernameLabel
.textContent
= this.username
;
68 usernameLabel
.title
= this.username
;
69 this.contentElement
.appendChild(usernameLabel
);
71 if (this.federation
) {
73 var federationDiv
= this.ownerDocument
.createElement('div');
74 federationDiv
.className
= 'federation';
75 federationDiv
.textContent
= this.federation
;
76 this.contentElement
.appendChild(federationDiv
);
78 // The stored password.
79 var passwordInputDiv
= this.ownerDocument
.createElement('div');
80 passwordInputDiv
.className
= 'password';
82 // The password input field.
83 var passwordInput
= this.ownerDocument
.createElement('input');
84 passwordInput
.type
= 'password';
85 passwordInput
.className
= 'inactive-password';
86 passwordInput
.readOnly
= true;
87 passwordInput
.value
= this.showPasswords_
? this.password
: '********';
88 passwordInputDiv
.appendChild(passwordInput
);
89 var deletableItem
= this;
90 passwordInput
.addEventListener('focus', function() {
91 deletableItem
.handleFocus();
93 this.passwordField
= passwordInput
;
94 this.setFocusable_(false);
96 // The show/hide button.
97 if (this.showPasswords_
) {
98 var button
= this.ownerDocument
.createElement('button');
100 button
.className
= 'list-inline-button custom-appearance';
101 button
.textContent
= loadTimeData
.getString('passwordShowButton');
102 button
.addEventListener('click', this.onClick_
.bind(this), true);
103 button
.addEventListener('mousedown', function(event
) {
104 // Don't focus on this button by mousedown.
105 event
.preventDefault();
106 // Don't handle list item selection. It causes focus change.
107 event
.stopPropagation();
109 button
.addEventListener('focus', function() {
110 deletableItem
.handleFocus();
112 passwordInputDiv
.appendChild(button
);
113 this.passwordShowButton
= button
;
115 this.contentElement
.appendChild(passwordInputDiv
);
121 selectionChanged: function() {
122 var input
= this.passwordField
;
123 var button
= this.passwordShowButton
;
124 // The button doesn't exist when passwords can't be shown.
129 input
.classList
.remove('inactive-password');
130 this.setFocusable_(true);
131 button
.hidden
= false;
134 input
.classList
.add('inactive-password');
135 this.setFocusable_(false);
136 button
.hidden
= true;
141 * Set the focusability of this row.
142 * @param {boolean} focusable
145 setFocusable_: function(focusable
) {
146 var tabIndex
= focusable
? 0 : -1;
147 this.passwordField
.tabIndex
= this.closeButtonElement
.tabIndex
= tabIndex
;
151 * Reveals the plain text password of this entry.
153 showPassword: function(password
) {
154 this.passwordField
.value
= password
;
155 this.passwordField
.type
= 'text';
157 var button
= this.passwordShowButton
;
159 button
.textContent
= loadTimeData
.getString('passwordHideButton');
163 * Hides the plain text password of this entry.
165 hidePassword: function() {
166 this.passwordField
.type
= 'password';
168 var button
= this.passwordShowButton
;
170 button
.textContent
= loadTimeData
.getString('passwordShowButton');
174 * Get the original index of this item in the data model.
175 * @return {number} The index.
178 getOriginalIndex_: function() {
179 var index
= this.dataItem
[ORIGINAL_DATA_INDEX
];
180 return index
? index
: this.dataModel
.indexOf(this.dataItem
);
184 * On-click event handler. Swaps the type of the input field from password
188 onClick_: function(event
) {
189 if (this.passwordField
.type
== 'password') {
190 // After the user is authenticated, showPassword() will be called.
191 PasswordManager
.requestShowPassword(this.getOriginalIndex_());
198 * Get and set the URL for the entry.
202 return this.dataItem
[URL_DATA_INDEX
];
205 this.dataItem
[URL_DATA_INDEX
] = url
;
209 * Get and set the username for the entry.
213 return this.dataItem
[USERNAME_DATA_INDEX
];
215 set username(username
) {
216 this.dataItem
[USERNAME_DATA_INDEX
] = username
;
220 * Get and set the password for the entry.
224 return this.dataItem
[PASSWORD_DATA_INDEX
];
226 set password(password
) {
227 this.dataItem
[PASSWORD_DATA_INDEX
] = password
;
231 * Get and set the federation for the entry.
235 return this.dataItem
[FEDERATION_DATA_INDEX
];
237 set federation(federation
) {
238 this.dataItem
[FEDERATION_DATA_INDEX
] = federation
;
243 * Creates a new PasswordExceptions list item.
244 * @param {Array} entry A pair of the form [url, username].
246 * @extends {options.DeletableItem}
248 function PasswordExceptionsListItem(entry
) {
249 var el
= cr
.doc
.createElement('div');
251 el
.__proto__
= PasswordExceptionsListItem
.prototype;
257 PasswordExceptionsListItem
.prototype = {
258 __proto__
: DeletableItem
.prototype,
261 * Call when an element is decorated as a list item.
263 decorate: function() {
264 DeletableItem
.prototype.decorate
.call(this);
266 // The URL of the site.
267 var urlLabel
= this.ownerDocument
.createElement('div');
268 urlLabel
.className
= 'url';
269 urlLabel
.classList
.add('favicon-cell');
270 urlLabel
.classList
.add('weakrtl');
271 urlLabel
.textContent
= this.url
;
273 // The favicon URL is prefixed with "origin/", which essentially removes
274 // the URL path past the top-level domain and ensures that a scheme (e.g.,
275 // http) is being used. This ensures that the favicon returned is the
276 // default favicon for the domain and that the URL has a scheme if none
277 // is present in the password manager.
278 urlLabel
.style
.backgroundImage
= getFaviconImageSet(
279 'origin/' + this.url
, 16);
280 this.contentElement
.appendChild(urlLabel
);
284 * Get the url for the entry.
288 return this.dataItem
;
296 * Create a new passwords list.
298 * @extends {options.DeletableItemList}
300 var PasswordsList
= cr
.ui
.define('list');
302 PasswordsList
.prototype = {
303 __proto__
: DeletableItemList
.prototype,
306 * Whether passwords can be revealed or not.
310 showPasswords_
: true,
313 decorate: function() {
314 DeletableItemList
.prototype.decorate
.call(this);
315 Preferences
.getInstance().addEventListener(
316 'profile.password_manager_allow_show_passwords',
317 this.onPreferenceChanged_
.bind(this));
318 this.addEventListener('focus', this.onFocus_
.bind(this));
322 * Listener for changes on the preference.
323 * @param {Event} event The preference update event.
326 onPreferenceChanged_: function(event
) {
327 this.showPasswords_
= event
.value
.value
;
333 * @param {Array} entry
335 createItem: function(entry
) {
336 var showPasswords
= this.showPasswords_
;
338 if (loadTimeData
.getBoolean('disableShowPasswords'))
339 showPasswords
= false;
341 return new PasswordListItem(this.dataModel
, entry
, showPasswords
);
345 deleteItemAtIndex: function(index
) {
346 var item
= this.dataModel
.item(index
);
347 if (item
&& item
[ORIGINAL_DATA_INDEX
] != undefined) {
348 // The fifth element, if present, is the original index to delete.
349 index
= item
[ORIGINAL_DATA_INDEX
];
351 PasswordManager
.removeSavedPassword(index
);
355 * The length of the list.
358 return this.dataModel
.length
;
362 * Will make to first row focusable if none are selected. This makes it
363 * possible to tab into the rows without pressing up/down first.
364 * @param {Event} e The focus event.
367 onFocus_: function(e
) {
368 if (!this.selectedItem
&& this.items
)
369 this.items
[0].setFocusable_(true);
374 * Create a new passwords list.
376 * @extends {options.DeletableItemList}
378 var PasswordExceptionsList
= cr
.ui
.define('list');
380 PasswordExceptionsList
.prototype = {
381 __proto__
: DeletableItemList
.prototype,
385 * @param {Array} entry
387 createItem: function(entry
) {
388 return new PasswordExceptionsListItem(entry
);
392 deleteItemAtIndex: function(index
) {
393 PasswordManager
.removePasswordException(index
);
397 * The length of the list.
400 return this.dataModel
.length
;
405 PasswordListItem
: PasswordListItem
,
406 PasswordExceptionsListItem
: PasswordExceptionsListItem
,
407 PasswordsList
: PasswordsList
,
408 PasswordExceptionsList
: PasswordExceptionsList
,