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