Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / options / password_manager.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', function() {
6   /** @const */ var Page = cr.ui.pageManager.Page;
7   /** @const */ var PageManager = cr.ui.pageManager.PageManager;
8   /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel;
9
10   /////////////////////////////////////////////////////////////////////////////
11   // PasswordManager class:
12
13   /**
14    * Encapsulated handling of password and exceptions page.
15    * @constructor
16    */
17   function PasswordManager() {
18     this.activeNavTab = null;
19     Page.call(this, 'passwords',
20               loadTimeData.getString('passwordsPageTabTitle'),
21               'password-manager');
22   }
23
24   cr.addSingletonGetter(PasswordManager);
25
26   PasswordManager.prototype = {
27     __proto__: Page.prototype,
28
29     /**
30      * The saved passwords list.
31      * @type {DeletableItemList}
32      * @private
33      */
34     savedPasswordsList_: null,
35
36     /**
37      * The password exceptions list.
38      * @type {DeletableItemList}
39      * @private
40      */
41     passwordExceptionsList_: null,
42
43     /**
44      * The timer id of the timer set on search query change events.
45      * @type {number}
46      * @private
47      */
48     queryDelayTimerId_: 0,
49
50     /**
51      * The most recent search query, or null if the query is empty.
52      * @type {?string}
53      * @private
54      */
55     lastQuery_: null,
56
57     /** @override */
58     initializePage: function() {
59       Page.prototype.initializePage.call(this);
60
61       $('password-manager-confirm').onclick = function() {
62         PageManager.closeOverlay();
63       };
64
65       $('password-search-box').addEventListener('search',
66           this.handleSearchQueryChange_.bind(this));
67
68       this.createSavedPasswordsList_();
69       this.createPasswordExceptionsList_();
70     },
71
72     /** @override */
73     canShowPage: function() {
74       return !(cr.isChromeOS && UIAccountTweaks.loggedInAsGuest());
75     },
76
77     /** @override */
78     didShowPage: function() {
79       // Updating the password lists may cause a blocking platform dialog pop up
80       // (Mac, Linux), so we delay this operation until the page is shown.
81       chrome.send('updatePasswordLists');
82       $('password-search-box').focus();
83     },
84
85     /**
86      * Creates, decorates and initializes the saved passwords list.
87      * @private
88      */
89     createSavedPasswordsList_: function() {
90       this.savedPasswordsList_ = $('saved-passwords-list');
91       options.passwordManager.PasswordsList.decorate(this.savedPasswordsList_);
92       this.savedPasswordsList_.autoExpands = true;
93     },
94
95     /**
96      * Creates, decorates and initializes the password exceptions list.
97      * @private
98      */
99     createPasswordExceptionsList_: function() {
100       this.passwordExceptionsList_ = $('password-exceptions-list');
101       options.passwordManager.PasswordExceptionsList.decorate(
102           this.passwordExceptionsList_);
103       this.passwordExceptionsList_.autoExpands = true;
104     },
105
106     /**
107      * Handles search query changes.
108      * @param {!Event} e The event object.
109      * @private
110      */
111     handleSearchQueryChange_: function(e) {
112       if (this.queryDelayTimerId_)
113         window.clearTimeout(this.queryDelayTimerId_);
114
115       // Searching cookies uses a timeout of 500ms. We use a shorter timeout
116       // because there are probably fewer passwords and we want the UI to be
117       // snappier since users will expect that it's "less work."
118       this.queryDelayTimerId_ = window.setTimeout(
119           this.searchPasswords_.bind(this), 250);
120     },
121
122     /**
123      * Search passwords using text in |password-search-box|.
124      * @private
125      */
126     searchPasswords_: function() {
127       this.queryDelayTimerId_ = 0;
128       var filter = $('password-search-box').value;
129       filter = (filter == '') ? null : filter;
130       if (this.lastQuery_ != filter) {
131         this.lastQuery_ = filter;
132         // Searching for passwords has the side effect of requerying the
133         // underlying password store. This is done intentionally, as on OS X and
134         // Linux they can change from outside and we won't be notified of it.
135         chrome.send('updatePasswordLists');
136       }
137     },
138
139     /**
140      * Updates the visibility of the list and empty list placeholder.
141      * @param {!List} list The list to toggle visilibility for.
142      */
143     updateListVisibility_: function(list) {
144       var empty = list.dataModel.length == 0;
145       var listPlaceHolderID = list.id + '-empty-placeholder';
146       list.hidden = empty;
147       $(listPlaceHolderID).hidden = !empty;
148     },
149
150     /**
151      * Updates the data model for the saved passwords list with the values from
152      * |entries|.
153      * @param {Array} entries The list of saved password data.
154      */
155     setSavedPasswordsList_: function(entries) {
156       if (this.lastQuery_) {
157         // Implement password searching here in javascript, rather than in C++.
158         // The number of saved passwords shouldn't be too big for us to handle.
159         var query = this.lastQuery_;
160         var filter = function(entry, index, list) {
161           // Search both URL and username.
162           if (entry[0].toLowerCase().indexOf(query.toLowerCase()) >= 0 ||
163               entry[1].toLowerCase().indexOf(query.toLowerCase()) >= 0) {
164             // Keep the original index so we can delete correctly. See also
165             // deleteItemAtIndex() in password_manager_list.js that uses this.
166             entry[3] = index;
167             return true;
168           }
169           return false;
170         };
171         entries = entries.filter(filter);
172       }
173       this.savedPasswordsList_.dataModel = new ArrayDataModel(entries);
174       this.updateListVisibility_(this.savedPasswordsList_);
175     },
176
177     /**
178      * Updates the data model for the password exceptions list with the values
179      * from |entries|.
180      * @param {Array} entries The list of password exception data.
181      */
182     setPasswordExceptionsList_: function(entries) {
183       this.passwordExceptionsList_.dataModel = new ArrayDataModel(entries);
184       this.updateListVisibility_(this.passwordExceptionsList_);
185     },
186
187     /**
188      * Reveals the password for a saved password entry. This is called by the
189      * backend after it has authenticated the user.
190      * @param {number} index The original index of the entry in the model.
191      * @param {string} password The saved password.
192      */
193     showPassword_: function(index, password) {
194       var model = this.savedPasswordsList_.dataModel;
195       if (this.lastQuery_) {
196         // When a filter is active, |index| does not represent the current
197         // index in the model, but each entry stores its original index, so
198         // we can find the item using a linear search.
199         for (var i = 0; i < model.length; ++i) {
200           if (model.item(i)[3] == index) {
201             index = i;
202             break;
203           }
204         }
205       }
206
207       // Reveal the password in the UI.
208       var item = this.savedPasswordsList_.getListItemByIndex(index);
209       item.showPassword(password);
210     },
211   };
212
213   /**
214    * Removes a saved password.
215    * @param {number} rowIndex indicating the row to remove.
216    */
217   PasswordManager.removeSavedPassword = function(rowIndex) {
218       chrome.send('removeSavedPassword', [String(rowIndex)]);
219   };
220
221   /**
222    * Removes a password exception.
223    * @param {number} rowIndex indicating the row to remove.
224    */
225   PasswordManager.removePasswordException = function(rowIndex) {
226       chrome.send('removePasswordException', [String(rowIndex)]);
227   };
228
229   PasswordManager.requestShowPassword = function(index) {
230     chrome.send('requestShowPassword', [index]);
231   };
232
233   // Forward public APIs to private implementations on the singleton instance.
234   [
235     'setSavedPasswordsList',
236     'setPasswordExceptionsList',
237     'showPassword'
238    ].forEach(function(name) {
239      PasswordManager[name] = function() {
240       var instance = PasswordManager.getInstance();
241       return instance[name + '_'].apply(instance, arguments);
242     };
243   });
244
245   // Export
246   return {
247     PasswordManager: PasswordManager
248   };
249
250 });