Home | History | Annotate | Download | only in options
      1 // Copyright (c) 2010 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 ArrayDataModel = cr.ui.ArrayDataModel;
      7   const DeletableItemList = options.DeletableItemList;
      8   const DeletableItem = options.DeletableItem;
      9   const List = cr.ui.List;
     10 
     11   /**
     12    * Creates a new passwords list item.
     13    * @param {Array} entry An array of the form [url, username, password].
     14    * @constructor
     15    * @extends {cr.ui.ListItem}
     16    */
     17   function PasswordListItem(entry, showPasswords) {
     18     var el = cr.doc.createElement('div');
     19     el.dataItem = entry;
     20     el.__proto__ = PasswordListItem.prototype;
     21     el.decorate(showPasswords);
     22 
     23     return el;
     24   }
     25 
     26   PasswordListItem.prototype = {
     27     __proto__: DeletableItem.prototype,
     28 
     29     /** @inheritDoc */
     30     decorate: function(showPasswords) {
     31       DeletableItem.prototype.decorate.call(this);
     32 
     33       // The URL of the site.
     34       var urlLabel = this.ownerDocument.createElement('div');
     35       urlLabel.classList.add('favicon-cell');
     36       urlLabel.classList.add('url');
     37       urlLabel.textContent = this.url;
     38       urlLabel.style.backgroundImage = url('chrome://favicon/' + this.url);
     39       this.contentElement.appendChild(urlLabel);
     40 
     41       // The stored username.
     42       var usernameLabel = this.ownerDocument.createElement('div');
     43       usernameLabel.className = 'name';
     44       usernameLabel.textContent = this.username;
     45       this.contentElement.appendChild(usernameLabel);
     46 
     47       // The stored password.
     48       var passwordInputDiv = this.ownerDocument.createElement('div');
     49       passwordInputDiv.className = 'password';
     50 
     51       // The password input field.
     52       var passwordInput = this.ownerDocument.createElement('input');
     53       passwordInput.type = 'password';
     54       passwordInput.className = 'inactive-password';
     55       passwordInput.readOnly = true;
     56       passwordInput.value = showPasswords ? this.password : "********";
     57       passwordInputDiv.appendChild(passwordInput);
     58 
     59       // The show/hide button.
     60       if (showPasswords) {
     61         var button = this.ownerDocument.createElement('button');
     62         button.classList.add('hidden');
     63         button.classList.add('password-button');
     64         button.textContent = localStrings.getString('passwordShowButton');
     65         button.addEventListener('click', this.onClick_, true);
     66         passwordInputDiv.appendChild(button);
     67       }
     68 
     69       this.contentElement.appendChild(passwordInputDiv);
     70     },
     71 
     72     /** @inheritDoc */
     73     selectionChanged: function() {
     74       var passwordInput = this.querySelector('input[type=password]');
     75       var textInput = this.querySelector('input[type=text]');
     76       var input = passwordInput || textInput;
     77       var button = input.nextSibling;
     78       // |button| doesn't exist when passwords can't be shown.
     79       if (!button)
     80         return;
     81       if (this.selected) {
     82         input.classList.remove('inactive-password');
     83         button.classList.remove('hidden');
     84       } else {
     85         input.classList.add('inactive-password');
     86         button.classList.add('hidden');
     87       }
     88     },
     89 
     90     /**
     91      * On-click event handler. Swaps the type of the input field from password
     92      * to text and back.
     93      * @private
     94      */
     95     onClick_: function(event) {
     96       // The password is the input element previous to the button.
     97       var button = event.currentTarget;
     98       var passwordInput = button.previousSibling;
     99       if (passwordInput.type == 'password') {
    100         passwordInput.type = 'text';
    101         button.textContent = localStrings.getString('passwordHideButton');
    102       } else {
    103         passwordInput.type = 'password';
    104         button.textContent = localStrings.getString('passwordShowButton');
    105       }
    106     },
    107 
    108     /**
    109      * Get and set the URL for the entry.
    110      * @type {string}
    111      */
    112     get url() {
    113       return this.dataItem[0];
    114     },
    115     set url(url) {
    116       this.dataItem[0] = url;
    117     },
    118 
    119     /**
    120      * Get and set the username for the entry.
    121      * @type {string}
    122      */
    123     get username() {
    124       return this.dataItem[1];
    125     },
    126     set username(username) {
    127       this.dataItem[1] = username;
    128     },
    129 
    130     /**
    131      * Get and set the password for the entry.
    132      * @type {string}
    133      */
    134     get password() {
    135       return this.dataItem[2];
    136     },
    137     set password(password) {
    138       this.dataItem[2] = password;
    139     },
    140   };
    141 
    142   /**
    143    * Creates a new PasswordExceptions list item.
    144    * @param {Array} entry A pair of the form [url, username].
    145    * @constructor
    146    * @extends {Deletable.ListItem}
    147    */
    148   function PasswordExceptionsListItem(entry) {
    149     var el = cr.doc.createElement('div');
    150     el.dataItem = entry;
    151     el.__proto__ = PasswordExceptionsListItem.prototype;
    152     el.decorate();
    153 
    154     return el;
    155   }
    156 
    157   PasswordExceptionsListItem.prototype = {
    158     __proto__: DeletableItem.prototype,
    159 
    160     /**
    161      * Call when an element is decorated as a list item.
    162      */
    163     decorate: function() {
    164       DeletableItem.prototype.decorate.call(this);
    165 
    166       // The URL of the site.
    167       var urlLabel = this.ownerDocument.createElement('div');
    168       urlLabel.className = 'url';
    169       urlLabel.classList.add('favicon-cell');
    170       urlLabel.textContent = this.url;
    171       urlLabel.style.backgroundImage = url('chrome://favicon/' + this.url);
    172       this.contentElement.appendChild(urlLabel);
    173     },
    174 
    175     /**
    176      * Get the url for the entry.
    177      * @type {string}
    178      */
    179     get url() {
    180       return this.dataItem;
    181     },
    182     set url(url) {
    183       this.dataItem = url;
    184     },
    185   };
    186 
    187   /**
    188    * Create a new passwords list.
    189    * @constructor
    190    * @extends {cr.ui.List}
    191    */
    192   var PasswordsList = cr.ui.define('list');
    193 
    194   PasswordsList.prototype = {
    195     __proto__: DeletableItemList.prototype,
    196 
    197     /**
    198      * Whether passwords can be revealed or not.
    199      * @type {boolean}
    200      * @private
    201      */
    202     showPasswords_: true,
    203 
    204     /** @inheritDoc */
    205     decorate: function() {
    206       DeletableItemList.prototype.decorate.call(this);
    207       Preferences.getInstance().addEventListener(
    208           "profile.password_manager_allow_show_passwords",
    209           this.onPreferenceChanged_.bind(this));
    210     },
    211 
    212     /**
    213      * Listener for changes on the preference.
    214      * @param {Event} event The preference update event.
    215      * @private
    216      */
    217     onPreferenceChanged_: function(event) {
    218       this.showPasswords_ = event.value.value;
    219       this.redraw();
    220     },
    221 
    222     /** @inheritDoc */
    223     createItem: function(entry) {
    224       return new PasswordListItem(entry, this.showPasswords_);
    225     },
    226 
    227     /** @inheritDoc */
    228     deleteItemAtIndex: function(index) {
    229       PasswordManager.removeSavedPassword(index);
    230     },
    231 
    232     /**
    233      * The length of the list.
    234      */
    235     get length() {
    236       return this.dataModel.length;
    237     },
    238   };
    239 
    240   /**
    241    * Create a new passwords list.
    242    * @constructor
    243    * @extends {cr.ui.List}
    244    */
    245   var PasswordExceptionsList = cr.ui.define('list');
    246 
    247   PasswordExceptionsList.prototype = {
    248     __proto__: DeletableItemList.prototype,
    249 
    250     /** @inheritDoc */
    251     createItem: function(entry) {
    252       return new PasswordExceptionsListItem(entry);
    253     },
    254 
    255     /** @inheritDoc */
    256     deleteItemAtIndex: function(index) {
    257       PasswordManager.removePasswordException(index);
    258     },
    259 
    260     /**
    261      * The length of the list.
    262      */
    263     get length() {
    264       return this.dataModel.length;
    265     },
    266   };
    267 
    268   return {
    269     PasswordListItem: PasswordListItem,
    270     PasswordExceptionsListItem: PasswordExceptionsListItem,
    271     PasswordsList: PasswordsList,
    272     PasswordExceptionsList: PasswordExceptionsList,
    273   };
    274 });
    275