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;
12 * Creates a new passwords list item.
13 * @param {ArrayDataModel} dataModel The data model that contains this item.
14 * @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.
16 * @param {boolean} showPasswords If true, add a button to the element to
17 * allow the user to reveal the saved password.
19 * @extends {cr.ui.ListItem}
21 function PasswordListItem(dataModel, entry, showPasswords) {
22 var el = cr.doc.createElement('div');
24 el.dataModel = dataModel;
25 el.__proto__ = PasswordListItem.prototype;
26 el.decorate(showPasswords);
31 PasswordListItem.prototype = {
32 __proto__: DeletableItem.prototype,
35 decorate: function(showPasswords) {
36 DeletableItem.prototype.decorate.call(this);
38 // The URL of the site.
39 var urlLabel = this.ownerDocument.createElement('div');
40 urlLabel.classList.add('favicon-cell');
41 urlLabel.classList.add('weakrtl');
42 urlLabel.classList.add('url');
43 urlLabel.setAttribute('title', this.url);
44 urlLabel.textContent = this.url;
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);
55 // The stored username.
56 var usernameLabel = this.ownerDocument.createElement('div');
57 usernameLabel.className = 'name';
58 usernameLabel.textContent = this.username;
59 this.contentElement.appendChild(usernameLabel);
61 // The stored password.
62 var passwordInputDiv = this.ownerDocument.createElement('div');
63 passwordInputDiv.className = 'password';
65 // The password input field.
66 var passwordInput = this.ownerDocument.createElement('input');
67 passwordInput.type = 'password';
68 passwordInput.className = 'inactive-password';
69 passwordInput.readOnly = true;
70 passwordInput.value = showPasswords ? this.password : '********';
71 passwordInputDiv.appendChild(passwordInput);
72 this.passwordField = passwordInput;
74 // The show/hide button.
76 var button = this.ownerDocument.createElement('button');
78 button.className = 'list-inline-button custom-appearance';
79 button.textContent = loadTimeData.getString('passwordShowButton');
80 button.addEventListener('click', this.onClick_.bind(this), true);
81 button.addEventListener('mousedown', function(event) {
82 // Don't focus on this button by mousedown.
83 event.preventDefault();
84 // Don't handle list item selection. It causes focus change.
85 event.stopPropagation();
87 passwordInputDiv.appendChild(button);
88 this.passwordShowButton = button;
91 this.contentElement.appendChild(passwordInputDiv);
95 selectionChanged: function() {
96 var input = this.passwordField;
97 var button = this.passwordShowButton;
98 // The button doesn't exist when passwords can't be shown.
103 input.classList.remove('inactive-password');
104 button.hidden = false;
106 input.classList.add('inactive-password');
107 button.hidden = true;
112 * Reveals the plain text password of this entry.
114 showPassword: function(password) {
115 this.passwordField.value = password;
116 this.passwordField.type = 'text';
118 var button = this.passwordShowButton;
120 button.textContent = loadTimeData.getString('passwordHideButton');
124 * Hides the plain text password of this entry.
126 hidePassword: function() {
127 this.passwordField.type = 'password';
129 var button = this.passwordShowButton;
131 button.textContent = loadTimeData.getString('passwordShowButton');
135 * Get the original index of this item in the data model.
136 * @return {number} The index.
139 getOriginalIndex_: function() {
140 var index = this.dataItem[3];
141 return index ? index : this.dataModel.indexOf(this.dataItem);
145 * On-click event handler. Swaps the type of the input field from password
149 onClick_: function(event) {
150 if (this.passwordField.type == 'password') {
151 // After the user is authenticated, showPassword() will be called.
152 PasswordManager.requestShowPassword(this.getOriginalIndex_());
159 * Get and set the URL for the entry.
163 return this.dataItem[0];
166 this.dataItem[0] = url;
170 * Get and set the username for the entry.
174 return this.dataItem[1];
176 set username(username) {
177 this.dataItem[1] = username;
181 * Get and set the password for the entry.
185 return this.dataItem[2];
187 set password(password) {
188 this.dataItem[2] = password;
193 * Creates a new PasswordExceptions list item.
194 * @param {Array} entry A pair of the form [url, username].
196 * @extends {Deletable.ListItem}
198 function PasswordExceptionsListItem(entry) {
199 var el = cr.doc.createElement('div');
201 el.__proto__ = PasswordExceptionsListItem.prototype;
207 PasswordExceptionsListItem.prototype = {
208 __proto__: DeletableItem.prototype,
211 * Call when an element is decorated as a list item.
213 decorate: function() {
214 DeletableItem.prototype.decorate.call(this);
216 // The URL of the site.
217 var urlLabel = this.ownerDocument.createElement('div');
218 urlLabel.className = 'url';
219 urlLabel.classList.add('favicon-cell');
220 urlLabel.classList.add('weakrtl');
221 urlLabel.textContent = this.url;
223 // The favicon URL is prefixed with "origin/", which essentially removes
224 // the URL path past the top-level domain and ensures that a scheme (e.g.,
225 // http) is being used. This ensures that the favicon returned is the
226 // default favicon for the domain and that the URL has a scheme if none
227 // is present in the password manager.
228 urlLabel.style.backgroundImage = getFaviconImageSet(
229 'origin/' + this.url, 16);
230 this.contentElement.appendChild(urlLabel);
234 * Get the url for the entry.
238 return this.dataItem;
246 * Create a new passwords list.
248 * @extends {cr.ui.List}
250 var PasswordsList = cr.ui.define('list');
252 PasswordsList.prototype = {
253 __proto__: DeletableItemList.prototype,
256 * Whether passwords can be revealed or not.
260 showPasswords_: true,
263 decorate: function() {
264 DeletableItemList.prototype.decorate.call(this);
265 Preferences.getInstance().addEventListener(
266 'profile.password_manager_allow_show_passwords',
267 this.onPreferenceChanged_.bind(this));
271 * Listener for changes on the preference.
272 * @param {Event} event The preference update event.
275 onPreferenceChanged_: function(event) {
276 this.showPasswords_ = event.value.value;
281 createItem: function(entry) {
282 return new PasswordListItem(this.dataModel, entry, this.showPasswords_);
286 deleteItemAtIndex: function(index) {
287 var item = this.dataModel.item(index);
288 if (item && item.length > 3) {
289 // The fourth element, if present, is the original index to delete.
292 PasswordManager.removeSavedPassword(index);
296 * The length of the list.
299 return this.dataModel.length;
304 * Create a new passwords list.
306 * @extends {cr.ui.List}
308 var PasswordExceptionsList = cr.ui.define('list');
310 PasswordExceptionsList.prototype = {
311 __proto__: DeletableItemList.prototype,
314 createItem: function(entry) {
315 return new PasswordExceptionsListItem(entry);
319 deleteItemAtIndex: function(index) {
320 PasswordManager.removePasswordException(index);
324 * The length of the list.
327 return this.dataModel.length;
332 PasswordListItem: PasswordListItem,
333 PasswordExceptionsListItem: PasswordExceptionsListItem,
334 PasswordsList: PasswordsList,
335 PasswordExceptionsList: PasswordExceptionsList,