- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / options / password_manager_list.js
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.
4
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;
10
11   /**
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.
18    * @constructor
19    * @extends {cr.ui.ListItem}
20    */
21   function PasswordListItem(dataModel, entry, showPasswords) {
22     var el = cr.doc.createElement('div');
23     el.dataItem = entry;
24     el.dataModel = dataModel;
25     el.__proto__ = PasswordListItem.prototype;
26     el.decorate(showPasswords);
27
28     return el;
29   }
30
31   PasswordListItem.prototype = {
32     __proto__: DeletableItem.prototype,
33
34     /** @override */
35     decorate: function(showPasswords) {
36       DeletableItem.prototype.decorate.call(this);
37
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;
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       this.contentElement.appendChild(usernameLabel);
60
61       // The stored password.
62       var passwordInputDiv = this.ownerDocument.createElement('div');
63       passwordInputDiv.className = 'password';
64
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;
73
74       // The show/hide button.
75       if (showPasswords) {
76         var button = this.ownerDocument.createElement('button');
77         button.hidden = true;
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();
86         }, false);
87         passwordInputDiv.appendChild(button);
88         this.passwordShowButton = button;
89       }
90
91       this.contentElement.appendChild(passwordInputDiv);
92     },
93
94     /** @override */
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.
99       if (!button)
100         return;
101
102       if (this.selected) {
103         input.classList.remove('inactive-password');
104         button.hidden = false;
105       } else {
106         input.classList.add('inactive-password');
107         button.hidden = true;
108       }
109     },
110
111     /**
112      * Reveals the plain text password of this entry.
113      */
114     showPassword: function(password) {
115       this.passwordField.value = password;
116       this.passwordField.type = 'text';
117
118       var button = this.passwordShowButton;
119       if (button)
120         button.textContent = loadTimeData.getString('passwordHideButton');
121     },
122
123     /**
124      * Hides the plain text password of this entry.
125      */
126     hidePassword: function() {
127       this.passwordField.type = 'password';
128
129       var button = this.passwordShowButton;
130       if (button)
131         button.textContent = loadTimeData.getString('passwordShowButton');
132     },
133
134     /**
135      * Get the original index of this item in the data model.
136      * @return {number} The index.
137      * @private
138      */
139     getOriginalIndex_: function() {
140       var index = this.dataItem[3];
141       return index ? index : this.dataModel.indexOf(this.dataItem);
142     },
143
144     /**
145      * On-click event handler. Swaps the type of the input field from password
146      * to text and back.
147      * @private
148      */
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_());
153       } else {
154         this.hidePassword();
155       }
156     },
157
158     /**
159      * Get and set the URL for the entry.
160      * @type {string}
161      */
162     get url() {
163       return this.dataItem[0];
164     },
165     set url(url) {
166       this.dataItem[0] = url;
167     },
168
169     /**
170      * Get and set the username for the entry.
171      * @type {string}
172      */
173     get username() {
174       return this.dataItem[1];
175     },
176     set username(username) {
177       this.dataItem[1] = username;
178     },
179
180     /**
181      * Get and set the password for the entry.
182      * @type {string}
183      */
184     get password() {
185       return this.dataItem[2];
186     },
187     set password(password) {
188       this.dataItem[2] = password;
189     },
190   };
191
192   /**
193    * Creates a new PasswordExceptions list item.
194    * @param {Array} entry A pair of the form [url, username].
195    * @constructor
196    * @extends {Deletable.ListItem}
197    */
198   function PasswordExceptionsListItem(entry) {
199     var el = cr.doc.createElement('div');
200     el.dataItem = entry;
201     el.__proto__ = PasswordExceptionsListItem.prototype;
202     el.decorate();
203
204     return el;
205   }
206
207   PasswordExceptionsListItem.prototype = {
208     __proto__: DeletableItem.prototype,
209
210     /**
211      * Call when an element is decorated as a list item.
212      */
213     decorate: function() {
214       DeletableItem.prototype.decorate.call(this);
215
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;
222
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);
231     },
232
233     /**
234      * Get the url for the entry.
235      * @type {string}
236      */
237     get url() {
238       return this.dataItem;
239     },
240     set url(url) {
241       this.dataItem = url;
242     },
243   };
244
245   /**
246    * Create a new passwords list.
247    * @constructor
248    * @extends {cr.ui.List}
249    */
250   var PasswordsList = cr.ui.define('list');
251
252   PasswordsList.prototype = {
253     __proto__: DeletableItemList.prototype,
254
255     /**
256      * Whether passwords can be revealed or not.
257      * @type {boolean}
258      * @private
259      */
260     showPasswords_: true,
261
262     /** @override */
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));
268     },
269
270     /**
271      * Listener for changes on the preference.
272      * @param {Event} event The preference update event.
273      * @private
274      */
275     onPreferenceChanged_: function(event) {
276       this.showPasswords_ = event.value.value;
277       this.redraw();
278     },
279
280     /** @override */
281     createItem: function(entry) {
282       return new PasswordListItem(this.dataModel, entry, this.showPasswords_);
283     },
284
285     /** @override */
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.
290         index = item[3];
291       }
292       PasswordManager.removeSavedPassword(index);
293     },
294
295     /**
296      * The length of the list.
297      */
298     get length() {
299       return this.dataModel.length;
300     },
301   };
302
303   /**
304    * Create a new passwords list.
305    * @constructor
306    * @extends {cr.ui.List}
307    */
308   var PasswordExceptionsList = cr.ui.define('list');
309
310   PasswordExceptionsList.prototype = {
311     __proto__: DeletableItemList.prototype,
312
313     /** @override */
314     createItem: function(entry) {
315       return new PasswordExceptionsListItem(entry);
316     },
317
318     /** @override */
319     deleteItemAtIndex: function(index) {
320       PasswordManager.removePasswordException(index);
321     },
322
323     /**
324      * The length of the list.
325      */
326     get length() {
327       return this.dataModel.length;
328     },
329   };
330
331   return {
332     PasswordListItem: PasswordListItem,
333     PasswordExceptionsListItem: PasswordExceptionsListItem,
334     PasswordsList: PasswordsList,
335     PasswordExceptionsList: PasswordExceptionsList,
336   };
337 });