Upstream version 10.39.225.0
[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 {cr.ui.ArrayDataModel} dataModel The data model that contains this
14    *     item.
15    * @param {Array} entry An array of the form [url, username, password]. When
16    *     the list has been filtered, a fourth element [index] may be present.
17    * @param {boolean} showPasswords If true, add a button to the element to
18    *     allow the user to reveal the saved password.
19    * @constructor
20    * @extends {options.DeletableItem}
21    */
22   function PasswordListItem(dataModel, entry, showPasswords) {
23     var el = cr.doc.createElement('div');
24     el.dataItem = entry;
25     el.dataModel = dataModel;
26     el.__proto__ = PasswordListItem.prototype;
27     el.decorate(showPasswords);
28
29     return el;
30   }
31
32   PasswordListItem.prototype = {
33     __proto__: DeletableItem.prototype,
34
35     /** @override */
36     decorate: function(showPasswords) {
37       DeletableItem.prototype.decorate.call(this);
38
39       // The URL of the site.
40       var urlLabel = this.ownerDocument.createElement('div');
41       urlLabel.classList.add('favicon-cell');
42       urlLabel.classList.add('weakrtl');
43       urlLabel.classList.add('url');
44       urlLabel.setAttribute('title', this.url);
45       urlLabel.textContent = this.url;
46
47       // The favicon URL is prefixed with "origin/", which essentially removes
48       // the URL path past the top-level domain and ensures that a scheme (e.g.,
49       // http) is being used. This ensures that the favicon returned is the
50       // default favicon for the domain and that the URL has a scheme if none
51       // is present in the password manager.
52       urlLabel.style.backgroundImage = getFaviconImageSet(
53           'origin/' + this.url, 16);
54       this.contentElement.appendChild(urlLabel);
55
56       // The stored username.
57       var usernameLabel = this.ownerDocument.createElement('div');
58       usernameLabel.className = 'name';
59       usernameLabel.textContent = this.username;
60       usernameLabel.title = this.username;
61       this.contentElement.appendChild(usernameLabel);
62
63       // The stored password.
64       var passwordInputDiv = this.ownerDocument.createElement('div');
65       passwordInputDiv.className = 'password';
66
67       // The password input field.
68       var passwordInput = this.ownerDocument.createElement('input');
69       passwordInput.type = 'password';
70       passwordInput.className = 'inactive-password';
71       passwordInput.readOnly = true;
72       passwordInput.value = showPasswords ? this.password : '********';
73       passwordInputDiv.appendChild(passwordInput);
74       this.passwordField = passwordInput;
75
76       // The show/hide button.
77       if (showPasswords) {
78         var button = this.ownerDocument.createElement('button');
79         button.hidden = true;
80         button.className = 'list-inline-button custom-appearance';
81         button.textContent = loadTimeData.getString('passwordShowButton');
82         button.addEventListener('click', this.onClick_.bind(this), true);
83         button.addEventListener('mousedown', function(event) {
84           // Don't focus on this button by mousedown.
85           event.preventDefault();
86           // Don't handle list item selection. It causes focus change.
87           event.stopPropagation();
88         }, false);
89         passwordInputDiv.appendChild(button);
90         this.passwordShowButton = button;
91       }
92
93       this.contentElement.appendChild(passwordInputDiv);
94     },
95
96     /** @override */
97     selectionChanged: function() {
98       var input = this.passwordField;
99       var button = this.passwordShowButton;
100       // The button doesn't exist when passwords can't be shown.
101       if (!button)
102         return;
103
104       if (this.selected) {
105         input.classList.remove('inactive-password');
106         button.hidden = false;
107       } else {
108         input.classList.add('inactive-password');
109         button.hidden = true;
110       }
111     },
112
113     /**
114      * Reveals the plain text password of this entry.
115      */
116     showPassword: function(password) {
117       this.passwordField.value = password;
118       this.passwordField.type = 'text';
119
120       var button = this.passwordShowButton;
121       if (button)
122         button.textContent = loadTimeData.getString('passwordHideButton');
123     },
124
125     /**
126      * Hides the plain text password of this entry.
127      */
128     hidePassword: function() {
129       this.passwordField.type = 'password';
130
131       var button = this.passwordShowButton;
132       if (button)
133         button.textContent = loadTimeData.getString('passwordShowButton');
134     },
135
136     /**
137      * Get the original index of this item in the data model.
138      * @return {number} The index.
139      * @private
140      */
141     getOriginalIndex_: function() {
142       var index = this.dataItem[3];
143       return index ? index : this.dataModel.indexOf(this.dataItem);
144     },
145
146     /**
147      * On-click event handler. Swaps the type of the input field from password
148      * to text and back.
149      * @private
150      */
151     onClick_: function(event) {
152       if (this.passwordField.type == 'password') {
153         // After the user is authenticated, showPassword() will be called.
154         PasswordManager.requestShowPassword(this.getOriginalIndex_());
155       } else {
156         this.hidePassword();
157       }
158     },
159
160     /**
161      * Get and set the URL for the entry.
162      * @type {string}
163      */
164     get url() {
165       return this.dataItem[0];
166     },
167     set url(url) {
168       this.dataItem[0] = url;
169     },
170
171     /**
172      * Get and set the username for the entry.
173      * @type {string}
174      */
175     get username() {
176       return this.dataItem[1];
177     },
178     set username(username) {
179       this.dataItem[1] = username;
180     },
181
182     /**
183      * Get and set the password for the entry.
184      * @type {string}
185      */
186     get password() {
187       return this.dataItem[2];
188     },
189     set password(password) {
190       this.dataItem[2] = password;
191     },
192   };
193
194   /**
195    * Creates a new PasswordExceptions list item.
196    * @param {Array} entry A pair of the form [url, username].
197    * @constructor
198    * @extends {options.DeletableItem}
199    */
200   function PasswordExceptionsListItem(entry) {
201     var el = cr.doc.createElement('div');
202     el.dataItem = entry;
203     el.__proto__ = PasswordExceptionsListItem.prototype;
204     el.decorate();
205
206     return el;
207   }
208
209   PasswordExceptionsListItem.prototype = {
210     __proto__: DeletableItem.prototype,
211
212     /**
213      * Call when an element is decorated as a list item.
214      */
215     decorate: function() {
216       DeletableItem.prototype.decorate.call(this);
217
218       // The URL of the site.
219       var urlLabel = this.ownerDocument.createElement('div');
220       urlLabel.className = 'url';
221       urlLabel.classList.add('favicon-cell');
222       urlLabel.classList.add('weakrtl');
223       urlLabel.textContent = this.url;
224
225       // The favicon URL is prefixed with "origin/", which essentially removes
226       // the URL path past the top-level domain and ensures that a scheme (e.g.,
227       // http) is being used. This ensures that the favicon returned is the
228       // default favicon for the domain and that the URL has a scheme if none
229       // is present in the password manager.
230       urlLabel.style.backgroundImage = getFaviconImageSet(
231           'origin/' + this.url, 16);
232       this.contentElement.appendChild(urlLabel);
233     },
234
235     /**
236      * Get the url for the entry.
237      * @type {string}
238      */
239     get url() {
240       return this.dataItem;
241     },
242     set url(url) {
243       this.dataItem = url;
244     },
245   };
246
247   /**
248    * Create a new passwords list.
249    * @constructor
250    * @extends {options.DeletableItemList}
251    */
252   var PasswordsList = cr.ui.define('list');
253
254   PasswordsList.prototype = {
255     __proto__: DeletableItemList.prototype,
256
257     /**
258      * Whether passwords can be revealed or not.
259      * @type {boolean}
260      * @private
261      */
262     showPasswords_: true,
263
264     /** @override */
265     decorate: function() {
266       DeletableItemList.prototype.decorate.call(this);
267       Preferences.getInstance().addEventListener(
268           'profile.password_manager_allow_show_passwords',
269           this.onPreferenceChanged_.bind(this));
270     },
271
272     /**
273      * Listener for changes on the preference.
274      * @param {Event} event The preference update event.
275      * @private
276      */
277     onPreferenceChanged_: function(event) {
278       this.showPasswords_ = event.value.value;
279       this.redraw();
280     },
281
282     /**
283      * @override
284      * @param {Array} entry
285      */
286     createItem: function(entry) {
287       var showPasswords = this.showPasswords_;
288
289       if (loadTimeData.getBoolean('disableShowPasswords'))
290         showPasswords = false;
291
292       return new PasswordListItem(this.dataModel, entry, showPasswords);
293     },
294
295     /** @override */
296     deleteItemAtIndex: function(index) {
297       var item = this.dataModel.item(index);
298       if (item && item.length > 3) {
299         // The fourth element, if present, is the original index to delete.
300         index = item[3];
301       }
302       PasswordManager.removeSavedPassword(index);
303     },
304
305     /**
306      * The length of the list.
307      */
308     get length() {
309       return this.dataModel.length;
310     },
311   };
312
313   /**
314    * Create a new passwords list.
315    * @constructor
316    * @extends {cr.ui.List}
317    */
318   var PasswordExceptionsList = cr.ui.define('list');
319
320   PasswordExceptionsList.prototype = {
321     __proto__: DeletableItemList.prototype,
322
323     /**
324      * @override
325      * @param {Array} entry
326      */
327     createItem: function(entry) {
328       return new PasswordExceptionsListItem(entry);
329     },
330
331     /** @override */
332     deleteItemAtIndex: function(index) {
333       PasswordManager.removePasswordException(index);
334     },
335
336     /**
337      * The length of the list.
338      */
339     get length() {
340       return this.dataModel.length;
341     },
342   };
343
344   return {
345     PasswordListItem: PasswordListItem,
346     PasswordExceptionsListItem: PasswordExceptionsListItem,
347     PasswordsList: PasswordsList,
348     PasswordExceptionsList: PasswordExceptionsList,
349   };
350 });