Home | History | Annotate | Download | only in chromeos
      1 // Copyright (c) 2011 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.internet', function() {
      6 
      7   /**
      8    * Network settings constants. These enums usually match their C++
      9    * counterparts.
     10    */
     11   function Constants() {}
     12   // Minimum length for wireless network password.
     13   Constants.MIN_WIRELESS_PASSWORD_LENGTH = 5;
     14   // Minimum length for SSID name.
     15   Constants.MIN_WIRELESS_SSID_LENGTH = 1;
     16   // Cellular activation states:
     17   Constants.ACTIVATION_STATE_UNKNOWN             = 0;
     18   Constants.ACTIVATION_STATE_ACTIVATED           = 1;
     19   Constants.ACTIVATION_STATE_ACTIVATING          = 2;
     20   Constants.ACTIVATION_STATE_NOT_ACTIVATED       = 3;
     21   Constants.ACTIVATION_STATE_PARTIALLY_ACTIVATED = 4;
     22   // Network types:
     23   Constants.TYPE_UNKNOWN   = 0;
     24   Constants.TYPE_ETHERNET  = 1;
     25   Constants.TYPE_WIFI      = 2;
     26   Constants.TYPE_WIMAX     = 3;
     27   Constants.TYPE_BLUETOOTH = 4;
     28   Constants.TYPE_CELLULAR  = 5;
     29 
     30   /**
     31    * Creates a new network list div.
     32    * @param {Object=} opt_propertyBag Optional properties.
     33    * @constructor
     34    * @extends {HTMLDivElement}
     35    */
     36   var NetworkElement = cr.ui.define('div');
     37 
     38   NetworkElement.prototype = {
     39     __proto__: HTMLDivElement.prototype,
     40 
     41     /** @inheritDoc */
     42     decorate: function() {
     43       this.addEventListener('click', this.handleClick_);
     44     },
     45 
     46     /**
     47      * Loads given network list.
     48      * @param {Array} networks An array of network object.
     49      */
     50     load: function(networks) {
     51       this.textContent = '';
     52 
     53       for (var i = 0; i < networks.length; ++i) {
     54         this.appendChild(new NetworkItem(networks[i]));
     55       }
     56     },
     57 
     58     /**
     59      * Handles click on network list and triggers actions when clicked on
     60      * a NetworkListItem button.
     61      * @private
     62      * @param {!Event} e The click event object.
     63      */
     64     handleClick_: function(e) {
     65       // We shouldn't respond to click events selecting an input,
     66       // so return on those.
     67       if (e.target.tagName == 'INPUT') {
     68         return;
     69       }
     70       // Handle left button click
     71       if (e.button == 0) {
     72         var el = e.target;
     73         // If click is on action buttons of a network item.
     74         if (!(el.buttonType && el.networkType && el.servicePath)) {
     75           if (el.buttonType) {
     76             return;
     77           }
     78           // If click is on a network item or its label, walk up the DOM tree
     79           // to find the network item.
     80           var item = el;
     81           while (item && !item.data) {
     82             item = item.parentNode;
     83           }
     84           if (item.connecting)
     85             return;
     86 
     87           if (item) {
     88             var data = item.data;
     89             // Don't try to connect to Ethernet or unactivated Cellular.
     90             if (data && (data.networkType == 1 ||
     91                         (data.networkType == 5 && data.activation_state != 1)))
     92               return;
     93             for (var i = 0; i < this.childNodes.length; i++) {
     94               if (this.childNodes[i] != item)
     95                 this.childNodes[i].hidePassword();
     96             }
     97             InternetOptions.unlockUpdates();
     98             // If clicked on other networks item.
     99             if (data && data.servicePath == '?') {
    100               if (InternetOptions.useSettingsUI &&
    101                   data.type != options.internet.Constants.TYPE_CELLULAR) {
    102                 item.showOtherLogin();
    103               } else {
    104                 chrome.send('buttonClickCallback',
    105                             [String(data.networkType),
    106                              data.servicePath,
    107                              'connect']);
    108               }
    109             }
    110           }
    111         }
    112       }
    113     }
    114   };
    115 
    116   /**
    117    * Creates a new network item.
    118    * @param {Object} network The network this represents.
    119    * @constructor
    120    * @extends {HTMLDivElement}
    121    */
    122   function NetworkItem(network) {
    123     var el = cr.doc.createElement('div');
    124     el.data = {
    125       servicePath: network[0],
    126       networkName: network[1],
    127       networkStatus: network[2],
    128       networkType: network[3],
    129       connected: network[4],
    130       connecting: network[5],
    131       iconURL: network[6],
    132       remembered: network[7],
    133       activation_state: network[8],
    134       needs_new_plan: network[9],
    135       connectable: network[10]
    136     };
    137     NetworkItem.decorate(el);
    138     return el;
    139   }
    140 
    141 
    142   /**
    143    * Decorates an element as a network item.
    144    * @param {!HTMLElement} el The element to decorate.
    145    */
    146   NetworkItem.decorate = function(el) {
    147     el.__proto__ = NetworkItem.prototype;
    148     el.decorate();
    149   };
    150 
    151   NetworkItem.prototype = {
    152     __proto__: HTMLDivElement.prototype,
    153 
    154     /** @inheritDoc */
    155     decorate: function() {
    156       this.className = 'network-item';
    157       this.connected = this.data.connected;
    158       this.connectable = this.data.connectable;
    159       this.other = this.data.servicePath == '?';
    160       this.id = this.data.servicePath;
    161       // textDiv holds icon, name and status text.
    162       var textDiv = this.ownerDocument.createElement('div');
    163       textDiv.className = 'network-item-text';
    164       if (this.data.iconURL) {
    165         textDiv.style.backgroundImage = url(this.data.iconURL);
    166       }
    167 
    168       var nameEl = this.ownerDocument.createElement('div');
    169       nameEl.className = 'network-name-label';
    170       nameEl.textContent = this.data.networkName;
    171       textDiv.appendChild(nameEl);
    172 
    173       if (this.other) {
    174         // No status and buttons for "Other..."
    175         this.appendChild(textDiv);
    176         return;
    177       }
    178 
    179       // Only show status text for networks other than "remembered".
    180       if (!this.data.remembered) {
    181         var statusEl = this.ownerDocument.createElement('div');
    182         statusEl.className = 'network-status-label';
    183         statusEl.textContent = this.data.networkStatus;
    184         textDiv.appendChild(statusEl);
    185       }
    186 
    187       this.appendChild(textDiv);
    188 
    189       var spacerDiv = this.ownerDocument.createElement('div');
    190       spacerDiv.className = 'network-item-box-spacer';
    191       this.appendChild(spacerDiv);
    192 
    193       var buttonsDiv = this.ownerDocument.createElement('div');
    194       var self = this;
    195       if (!this.data.remembered) {
    196         var no_plan =
    197             this.data.networkType == Constants.TYPE_CELLULAR &&
    198             this.data.needs_new_plan;
    199         var show_activate =
    200           (this.data.networkType == Constants.TYPE_CELLULAR &&
    201            this.data.activation_state !=
    202                Constants.ACTIVATION_STATE_ACTIVATED &&
    203            this.data.activation_state !=
    204                Constants.ACTIVATION_STATE_ACTIVATING);
    205 
    206         // Show [Activate] button for non-activated Cellular network.
    207         if (show_activate || no_plan) {
    208           var button_name = no_plan ? 'buyplan_button' : 'activate_button';
    209           buttonsDiv.appendChild(
    210               this.createButton_(button_name, 'activate',
    211                                  function(e) {
    212                 chrome.send('buttonClickCallback',
    213                             [String(self.data.networkType),
    214                              self.data.servicePath,
    215                              'activate']);
    216               }));
    217         }
    218         // Show disconnect button if not ethernet.
    219         if (this.data.networkType != Constants.TYPE_ETHERNET &&
    220             this.data.connected) {
    221           buttonsDiv.appendChild(
    222               this.createButton_('disconnect_button', 'disconnect',
    223                                   function(e) {
    224                  chrome.send('buttonClickCallback',
    225                              [String(self.data.networkType),
    226                               self.data.servicePath,
    227                               'disconnect']);
    228                }));
    229         }
    230         if (!this.data.connected && !this.data.connecting) {
    231           // connect button (if not ethernet and not showing activate button)
    232           if (this.data.networkType != Constants.TYPE_ETHERNET &&
    233               !show_activate && !no_plan) {
    234             buttonsDiv.appendChild(
    235                 this.createButton_('connect_button', 'connect',
    236                                    function(e) {
    237                   chrome.send('buttonClickCallback',
    238                               [String(self.data.networkType),
    239                                self.data.servicePath,
    240                                'connect']);
    241                 }));
    242           }
    243         }
    244         if (this.data.connected ||
    245             this.data.networkType == Constants.TYPE_CELLULAR) {
    246           buttonsDiv.appendChild(
    247               this.createButton_('options_button', 'options',
    248                                  function(e) {
    249                 chrome.send('buttonClickCallback',
    250                             [String(self.data.networkType),
    251                              self.data.servicePath,
    252                              'options']);
    253               }));
    254         }
    255       } else {
    256         // Put "Forget this network" button.
    257         var button = this.createButton_('forget_button', 'forget',
    258                                         function(e) {
    259                        chrome.send('buttonClickCallback',
    260                                    [String(self.data.networkType),
    261                                    self.data.servicePath,
    262                                    'forget']);
    263                      });
    264         if (!AccountsOptions.currentUserIsOwner()) {
    265           // Disable this for guest non-Owners.
    266           button.disabled = true;
    267         }
    268 
    269         buttonsDiv.appendChild(button);
    270       }
    271       this.appendChild(buttonsDiv);
    272     },
    273 
    274     showPassword: function() {
    275       if (this.connecting)
    276         return;
    277 
    278       InternetOptions.lockUpdates();
    279 
    280       var passwordDiv = this.ownerDocument.createElement('div');
    281       passwordDiv.className = 'network-password';
    282       var passInput = this.ownerDocument.createElement('input');
    283       passwordDiv.appendChild(passInput);
    284       passInput.placeholder = localStrings.getString('inetPassPrompt');
    285       passInput.type = 'password';
    286       var buttonEl = this.ownerDocument.createElement('button');
    287       buttonEl.textContent = localStrings.getString('inetLogin');
    288       buttonEl.addEventListener('click', this.handleLogin_);
    289       buttonEl.servicePath = this.data.servicePath;
    290       buttonEl.style.right = '0';
    291       buttonEl.style.position = 'absolute';
    292       buttonEl.style.visibility = 'visible';
    293       buttonEl.disabled = true;
    294 
    295       var togglePassLabel = this.ownerDocument.createElement('label');
    296       togglePassLabel.style.display = 'inline';
    297       var togglePassSpan = this.ownerDocument.createElement('span');
    298       var togglePassCheckbox = this.ownerDocument.createElement('input');
    299       togglePassCheckbox.type = 'checkbox';
    300       togglePassCheckbox.checked = false;
    301       togglePassCheckbox.target = passInput;
    302       togglePassCheckbox.addEventListener('change', this.handleShowPass_);
    303       togglePassSpan.textContent = localStrings.getString('inetShowPass');
    304       togglePassLabel.appendChild(togglePassCheckbox);
    305       togglePassLabel.appendChild(togglePassSpan);
    306       passwordDiv.appendChild(togglePassLabel);
    307 
    308       // Disable login button if there is no password.
    309       passInput.addEventListener('keyup', function(e) {
    310         buttonEl.disabled =
    311           passInput.value.length < Constants.MIN_WIRELESS_PASSWORD_LENGTH;
    312       });
    313 
    314       passwordDiv.appendChild(buttonEl);
    315       this.connecting = true;
    316       this.appendChild(passwordDiv);
    317     },
    318 
    319     handleShowPass_: function(e) {
    320       var target = e.target;
    321       if (target.checked) {
    322         target.target.type = 'text';
    323       } else {
    324         target.target.type = 'password';
    325       }
    326     },
    327 
    328     hidePassword: function() {
    329       this.connecting = false;
    330       var children = this.childNodes;
    331       // Remove all password divs starting from the end.
    332       for (var i = children.length-1; i >= 0; i--) {
    333         if (children[i].className == 'network-password') {
    334           this.removeChild(children[i]);
    335         }
    336       }
    337     },
    338 
    339     showOtherLogin: function() {
    340       if (this.connecting)
    341         return;
    342 
    343       InternetOptions.lockUpdates();
    344 
    345       var ssidDiv = this.ownerDocument.createElement('div');
    346       ssidDiv.className = 'network-password';
    347       var ssidInput = this.ownerDocument.createElement('input');
    348       ssidInput.placeholder = localStrings.getString('inetSsidPrompt');
    349       ssidDiv.appendChild(ssidInput);
    350 
    351       var securityDiv = this.ownerDocument.createElement('div');
    352       securityDiv.className = 'network-password';
    353       var securityInput = this.ownerDocument.createElement('select');
    354       var securityNoneOption = this.ownerDocument.createElement('option');
    355       securityNoneOption.value = 'none';
    356       securityNoneOption.label = localStrings.getString('inetSecurityNone');
    357       securityInput.appendChild(securityNoneOption);
    358       var securityWEPOption = this.ownerDocument.createElement('option');
    359       securityWEPOption.value = 'wep';
    360       securityWEPOption.label = localStrings.getString('inetSecurityWEP');
    361       securityInput.appendChild(securityWEPOption);
    362       var securityWPAOption = this.ownerDocument.createElement('option');
    363       securityWPAOption.value = 'wpa';
    364       securityWPAOption.label = localStrings.getString('inetSecurityWPA');
    365       securityInput.appendChild(securityWPAOption);
    366       var securityRSNOption = this.ownerDocument.createElement('option');
    367       securityRSNOption.value = 'rsn';
    368       securityRSNOption.label = localStrings.getString('inetSecurityRSN');
    369       securityInput.appendChild(securityRSNOption);
    370       securityDiv.appendChild(securityInput);
    371 
    372       var passwordDiv = this.ownerDocument.createElement('div');
    373       passwordDiv.className = 'network-password';
    374       var passInput = this.ownerDocument.createElement('input');
    375       passInput.placeholder = localStrings.getString('inetPassPrompt');
    376       passInput.type = 'password';
    377       passInput.disabled = true;
    378       passwordDiv.appendChild(passInput);
    379 
    380       var togglePassLabel = this.ownerDocument.createElement('label');
    381       togglePassLabel.style.display = 'inline';
    382       var togglePassSpan = this.ownerDocument.createElement('span');
    383       var togglePassCheckbox = this.ownerDocument.createElement('input');
    384       togglePassCheckbox.type = 'checkbox';
    385       togglePassCheckbox.checked = false;
    386       togglePassCheckbox.target = passInput;
    387       togglePassCheckbox.addEventListener('change', this.handleShowPass_);
    388       togglePassSpan.textContent = localStrings.getString('inetShowPass');
    389       togglePassLabel.appendChild(togglePassCheckbox);
    390       togglePassLabel.appendChild(togglePassSpan);
    391       passwordDiv.appendChild(togglePassLabel);
    392 
    393       var buttonEl =
    394         this.createButton_('inetLogin', true, this.handleOtherLogin_);
    395       buttonEl.style.right = '0';
    396       buttonEl.style.position = 'absolute';
    397       buttonEl.style.visibility = 'visible';
    398       buttonEl.disabled = true;
    399       passwordDiv.appendChild(buttonEl);
    400 
    401       this.appendChild(ssidDiv);
    402       this.appendChild(securityDiv);
    403       this.appendChild(passwordDiv);
    404 
    405       securityInput.addEventListener('change', function(e) {
    406         // If changed to None, then disable passInput and clear it out.
    407         // Otherwise enable it.
    408         if (securityInput.value == 'none') {
    409           passInput.disabled = true;
    410           passInput.value = '';
    411         } else {
    412           passInput.disabled = false;
    413         }
    414       });
    415 
    416       var keyup_listener = function(e) {
    417         // Disable login button if ssid is not long enough or
    418         // password is not long enough (unless no security)
    419         var ssid_good =
    420           ssidInput.value.length >= Constants.MIN_WIRELESS_SSID_LENGTH;
    421         var pass_good =
    422           securityInput.value == 'none' ||
    423             passInput.value.length >= Constants.MIN_WIRELESS_PASSWORD_LENGTH;
    424         buttonEl.disabled = !ssid_good || !pass_good;
    425       };
    426       ssidInput.addEventListener('keyup', keyup_listener);
    427       securityInput.addEventListener('change', keyup_listener);
    428       passInput.addEventListener('keyup', keyup_listener);
    429       this.connecting = true;
    430     },
    431 
    432     handleLogin_: function(e) {
    433       // The user has clicked on the Login button. It's now safe to
    434       // unclock UI updates.
    435       InternetOptions.unlockUpdates();
    436       var el = e.target;
    437       var parent = el.parentNode;
    438       el.disabled = true;
    439       var input = parent.firstChild;
    440       input.disabled = true;
    441       chrome.send('loginToNetwork', [el.servicePath, input.value]);
    442     },
    443 
    444     handleOtherLogin_: function(e) {
    445       // See comments in handleLogin_().
    446       InternetOptions.unlockUpdates();
    447       var el = e.target;
    448       var parent = el.parentNode.parentNode;
    449       el.disabled = true;
    450       var ssid = parent.childNodes[1].firstChild;
    451       var sec = parent.childNodes[2].firstChild;
    452       var pass = parent.childNodes[3].firstChild;
    453       sec.disabled = true;
    454       ssid.disabled = true;
    455       pass.disabled = true;
    456       chrome.send('loginToOtherNetwork', [sec.value, ssid.value, pass.value]);
    457     },
    458 
    459     /**
    460      * Creates a button for interacting with a network.
    461      * @param {Object} name The name of the localStrings to use for the text.
    462      * @param {Object} type The type of button.
    463      */
    464     createButton_: function(name, type, callback) {
    465       var buttonEl = this.ownerDocument.createElement('button');
    466       buttonEl.buttonType = type;
    467       buttonEl.textContent = localStrings.getString(name);
    468       buttonEl.addEventListener('click', callback);
    469       return buttonEl;
    470     }
    471   };
    472 
    473   /**
    474    * Whether the underlying network is connected. Only used for display purpose.
    475    * @type {boolean}
    476    */
    477   cr.defineProperty(NetworkItem, 'connected', cr.PropertyKind.BOOL_ATTR);
    478 
    479   /**
    480    * Whether the underlying network is currently connecting.
    481    * Only used for display purpose.
    482    * @type {boolean}
    483    */
    484   cr.defineProperty(NetworkItem, 'connecting', cr.PropertyKind.BOOL_ATTR);
    485 
    486   /**
    487    * Whether the underlying network is an other network for adding networks.
    488    * Only used for display purpose.
    489    * @type {boolean}
    490    */
    491   cr.defineProperty(NetworkItem, 'other', cr.PropertyKind.BOOL_ATTR);
    492 
    493   /**
    494    * Whether the underlying network is connectable.
    495    * @type {boolean}
    496    */
    497   cr.defineProperty(NetworkItem, 'connectable', cr.PropertyKind.BOOL_ATTR);
    498 
    499   return {
    500     Constants: Constants,
    501     NetworkElement: NetworkElement
    502   };
    503 });
    504