Home | History | Annotate | Download | only in chromeos
      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 // require: onc_data.js
      6 
      7 // NOTE(stevenjb): This code is in the process of being converted to be
      8 // compatible with the networkingPrivate extension API:
      9 // * The network property dictionaries are being converted to use ONC values.
     10 // * chrome.send calls will be replaced with an API object that simulates the
     11 //   networkingPrivate API. See network_config.js.
     12 // See crbug.com/279351 for more info.
     13 
     14 /** @typedef {{address: (string|undefined),
     15  *             gateway: (string|undefined),
     16  *             nameServers: (string|undefined),
     17  *             netmask: (string|undefined),
     18  *             prefixLength: (number|undefined)}}
     19  * @see chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
     20  */
     21 var IPInfo;
     22 
     23 /**
     24  * InternetDetailedInfo argument passed to showDetailedInfo.
     25  * @see chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
     26  * @typedef {{
     27  *   servicePath: string,
     28  *   showCarrierSelect: (boolean|undefined),
     29  *   showViewAccountButton: (boolean|undefined)
     30  * }}
     31  */
     32 var InternetDetailedInfo;
     33 
     34 cr.define('options.internet', function() {
     35   var OncData = cr.onc.OncData;
     36   var Page = cr.ui.pageManager.Page;
     37   var PageManager = cr.ui.pageManager.PageManager;
     38   /** @const */ var IPAddressField = options.internet.IPAddressField;
     39 
     40   /** @const */ var GoogleNameServersString = '8.8.4.4,8.8.8.8';
     41   /** @const */ var CarrierGenericUMTS = 'Generic UMTS';
     42 
     43   /**
     44    * Helper function to set hidden attribute for elements matching a selector.
     45    * @param {string} selector CSS selector for extracting a list of elements.
     46    * @param {boolean} hidden New hidden value.
     47    */
     48   function updateHidden(selector, hidden) {
     49     var elements = cr.doc.querySelectorAll(selector);
     50     for (var i = 0, el; el = elements[i]; i++) {
     51       el.hidden = hidden;
     52     }
     53   }
     54 
     55   /**
     56    * Helper function to update the properties of the data object from the
     57    * properties in the update object.
     58    * @param {Object} data Object to update.
     59    * @param {Object} update Object containing the updated properties.
     60    */
     61   function updateDataObject(data, update) {
     62     for (var prop in update) {
     63       if (prop in data)
     64         data[prop] = update[prop];
     65     }
     66   }
     67 
     68   /**
     69    * Monitor pref change of given element.
     70    * @param {Element} el Target element.
     71    */
     72   function observePrefsUI(el) {
     73     Preferences.getInstance().addEventListener(el.pref, handlePrefUpdate);
     74   }
     75 
     76   /**
     77    * UI pref change handler.
     78    * @param {Event} e The update event.
     79    */
     80   function handlePrefUpdate(e) {
     81     DetailsInternetPage.getInstance().updateControls();
     82   }
     83 
     84   /**
     85    * Simple helper method for converting a field to a string. It is used to
     86    * easily assign an empty string from fields that may be unknown or undefined.
     87    * @param {Object} value that should be converted to a string.
     88    * @return {string} the result.
     89    */
     90   function stringFromValue(value) {
     91     return value ? String(value) : '';
     92   }
     93 
     94   /**
     95    * @param {string} action An action to send to coreOptionsUserMetricsAction.
     96    */
     97   function sendChromeMetricsAction(action) {
     98     chrome.send('coreOptionsUserMetricsAction', [action]);
     99   }
    100 
    101   /**
    102    * Sends the 'checked' state of a control to chrome for a network.
    103    * @param {string} path The service path of the network.
    104    * @param {string} message The message to send to chrome.
    105    * @param {string} checkboxId The id of the checkbox with the value to send.
    106    * @param {string=} opt_action Optional action to record.
    107    */
    108   function sendCheckedIfEnabled(path, message, checkboxId, opt_action) {
    109     var checkbox = assertInstanceof($(checkboxId), HTMLInputElement);
    110     if (!checkbox.hidden && !checkbox.disabled) {
    111       chrome.send(message, [path, checkbox.checked ? 'true' : 'false']);
    112       if (opt_action)
    113         sendChromeMetricsAction(opt_action);
    114     }
    115   }
    116 
    117   /**
    118    * Send metrics to Chrome when the detailed page is opened.
    119    * @param {string} type The ONC type of the network being shown.
    120    * @param {string} state The ONC network state.
    121    */
    122   function sendShowDetailsMetrics(type, state) {
    123     if (type == 'WiFi') {
    124       sendChromeMetricsAction('Options_NetworkShowDetailsWifi');
    125       if (state != 'NotConnected')
    126         sendChromeMetricsAction('Options_NetworkShowDetailsWifiConnected');
    127     } else if (type == 'Cellular') {
    128       sendChromeMetricsAction('Options_NetworkShowDetailsCellular');
    129       if (state != 'NotConnected')
    130         sendChromeMetricsAction('Options_NetworkShowDetailsCellularConnected');
    131     } else if (type == 'VPN') {
    132       sendChromeMetricsAction('Options_NetworkShowDetailsVPN');
    133       if (state != 'NotConnected')
    134         sendChromeMetricsAction('Options_NetworkShowDetailsVPNConnected');
    135     }
    136   }
    137 
    138   /**
    139    * Returns the netmask as a string for a given prefix length.
    140    * @param {number} prefixLength The ONC routing prefix length.
    141    * @return {string} The corresponding netmask.
    142    */
    143   function prefixLengthToNetmask(prefixLength) {
    144     // Return the empty string for invalid inputs.
    145     if (prefixLength < 0 || prefixLength > 32)
    146       return '';
    147     var netmask = '';
    148     for (var i = 0; i < 4; ++i) {
    149       var remainder = 8;
    150       if (prefixLength >= 8) {
    151         prefixLength -= 8;
    152       } else {
    153         remainder = prefixLength;
    154         prefixLength = 0;
    155       }
    156       if (i > 0)
    157         netmask += '.';
    158       var value = 0;
    159       if (remainder != 0)
    160         value = ((2 << (remainder - 1)) - 1) << (8 - remainder);
    161       netmask += value.toString();
    162     }
    163     return netmask;
    164   }
    165 
    166   /////////////////////////////////////////////////////////////////////////////
    167   // DetailsInternetPage class:
    168 
    169   /**
    170    * Encapsulated handling of ChromeOS internet details overlay page.
    171    * @constructor
    172    * @extends {cr.ui.pageManager.Page}
    173    */
    174   function DetailsInternetPage() {
    175     // Cached Apn properties
    176     this.userApnIndex_ = -1;
    177     this.selectedApnIndex_ = -1;
    178     this.userApn_ = {};
    179     // We show the Proxy configuration tab for remembered networks and when
    180     // configuring a proxy from the login screen.
    181     this.showProxy_ = false;
    182     // In Chrome we sometimes want to enable the Cellular carrier select UI.
    183     this.showCarrierSelect_ = false;
    184     // In Chrome we sometimes want to show the 'View Account' button.
    185     this.showViewAccountButton_ = false;
    186 
    187     Page.call(this, 'detailsInternetPage', '', 'details-internet-page');
    188   }
    189 
    190   cr.addSingletonGetter(DetailsInternetPage);
    191 
    192   DetailsInternetPage.prototype = {
    193     __proto__: Page.prototype,
    194 
    195     /** @override */
    196     initializePage: function() {
    197       Page.prototype.initializePage.call(this);
    198       this.initializePageContents_();
    199       this.showNetworkDetails_();
    200     },
    201 
    202     /**
    203      * Auto-activates the network details dialog if network information
    204      * is included in the URL.
    205      */
    206     showNetworkDetails_: function() {
    207       var servicePath = parseQueryParams(window.location).servicePath;
    208       if (!servicePath || !servicePath.length)
    209         return;
    210       var networkType = '';  // ignored for 'showDetails'
    211       chrome.send('networkCommand', [networkType, servicePath, 'showDetails']);
    212     },
    213 
    214     /**
    215      * Initializes the contents of the page.
    216      */
    217     initializePageContents_: function() {
    218       $('details-internet-dismiss').addEventListener('click', function(event) {
    219         DetailsInternetPage.setDetails();
    220       });
    221 
    222       $('details-internet-login').addEventListener('click', function(event) {
    223         DetailsInternetPage.setDetails();
    224         DetailsInternetPage.loginFromDetails();
    225       });
    226 
    227       $('details-internet-disconnect').addEventListener('click',
    228                                                         function(event) {
    229         DetailsInternetPage.setDetails();
    230         DetailsInternetPage.disconnectNetwork();
    231       });
    232 
    233       $('details-internet-configure').addEventListener('click',
    234                                                        function(event) {
    235         DetailsInternetPage.setDetails();
    236         DetailsInternetPage.configureNetwork();
    237       });
    238 
    239       $('activate-details').addEventListener('click', function(event) {
    240         DetailsInternetPage.activateFromDetails();
    241       });
    242 
    243       $('view-account-details').addEventListener('click', function(event) {
    244         chrome.send('showMorePlanInfo',
    245                     [DetailsInternetPage.getInstance().servicePath_]);
    246         PageManager.closeOverlay();
    247       });
    248 
    249       $('cellular-apn-use-default').addEventListener('click', function(event) {
    250         DetailsInternetPage.getInstance().setDefaultApn_();
    251       });
    252 
    253       $('cellular-apn-set').addEventListener('click', function(event) {
    254         DetailsInternetPage.getInstance().setApn_($('cellular-apn').value);
    255       });
    256 
    257       $('cellular-apn-cancel').addEventListener('click', function(event) {
    258         DetailsInternetPage.getInstance().cancelApn_();
    259       });
    260 
    261       $('select-apn').addEventListener('change', function(event) {
    262         DetailsInternetPage.getInstance().selectApn_();
    263       });
    264 
    265       $('sim-card-lock-enabled').addEventListener('click', function(event) {
    266         var newValue = $('sim-card-lock-enabled').checked;
    267         // Leave value as is because user needs to enter PIN code first.
    268         // When PIN will be entered and value changed,
    269         // we'll update UI to reflect that change.
    270         $('sim-card-lock-enabled').checked = !newValue;
    271         var operation = newValue ? 'setLocked' : 'setUnlocked';
    272         chrome.send('simOperation', [operation]);
    273       });
    274       $('change-pin').addEventListener('click', function(event) {
    275         chrome.send('simOperation', ['changePin']);
    276       });
    277 
    278       // Proxy
    279       ['proxy-host-single-port',
    280        'secure-proxy-port',
    281        'socks-port',
    282        'ftp-proxy-port',
    283        'proxy-host-port'
    284       ].forEach(function(id) {
    285         options.PrefPortNumber.decorate($(id));
    286       });
    287 
    288       options.proxyexceptions.ProxyExceptions.decorate($('ignored-host-list'));
    289       $('remove-host').addEventListener('click',
    290                                         this.handleRemoveProxyExceptions_);
    291       $('add-host').addEventListener('click', this.handleAddProxyException_);
    292       $('direct-proxy').addEventListener('click', this.disableManualProxy_);
    293       $('manual-proxy').addEventListener('click', this.enableManualProxy_);
    294       $('auto-proxy').addEventListener('click', this.disableManualProxy_);
    295       $('proxy-all-protocols').addEventListener('click',
    296                                                 this.toggleSingleProxy_);
    297       $('proxy-use-pac-url').addEventListener('change',
    298                                               this.handleAutoConfigProxy_);
    299 
    300       observePrefsUI($('direct-proxy'));
    301       observePrefsUI($('manual-proxy'));
    302       observePrefsUI($('auto-proxy'));
    303       observePrefsUI($('proxy-all-protocols'));
    304       observePrefsUI($('proxy-use-pac-url'));
    305 
    306       $('ip-automatic-configuration-checkbox').addEventListener('click',
    307         this.handleIpAutoConfig_);
    308       $('automatic-dns-radio').addEventListener('click',
    309         this.handleNameServerTypeChange_);
    310       $('google-dns-radio').addEventListener('click',
    311         this.handleNameServerTypeChange_);
    312       $('user-dns-radio').addEventListener('click',
    313         this.handleNameServerTypeChange_);
    314 
    315       // We only load this string if we have the string data available
    316       // because the proxy settings page on the login screen re-uses the
    317       // proxy sub-page from the internet options, and it doesn't ever
    318       // show the DNS settings, so we don't need this string there.
    319       // The string isn't available because
    320       // chrome://settings-frame/strings.js (where the string is
    321       // stored) is not accessible from the login screen.
    322       // TODO(pneubeck): Remove this once i18n of the proxy dialog on the login
    323       // page is fixed. http://crbug.com/242865
    324       if (loadTimeData.data_) {
    325         $('google-dns-label').innerHTML =
    326             loadTimeData.getString('googleNameServers');
    327       }
    328     },
    329 
    330     /**
    331      * Handler for "add" event fired from userNameEdit.
    332      * @param {Event} e Add event fired from userNameEdit.
    333      * @private
    334      */
    335     handleAddProxyException_: function(e) {
    336       var exception = $('new-host').value;
    337       $('new-host').value = '';
    338 
    339       exception = exception.trim();
    340       if (exception)
    341         $('ignored-host-list').addException(exception);
    342     },
    343 
    344     /**
    345      * Handler for when the remove button is clicked
    346      * @param {Event} e The click event.
    347      * @private
    348      */
    349     handleRemoveProxyExceptions_: function(e) {
    350       var selectedItems = $('ignored-host-list').selectedItems;
    351       for (var x = 0; x < selectedItems.length; x++) {
    352         $('ignored-host-list').removeException(selectedItems[x]);
    353       }
    354     },
    355 
    356     /**
    357      * Handler for when the IP automatic configuration checkbox is clicked.
    358      * @param {Event} e The click event.
    359      * @private
    360      */
    361     handleIpAutoConfig_: function(e) {
    362       var checked = $('ip-automatic-configuration-checkbox').checked;
    363       var fields = [$('ip-address'), $('ip-netmask'), $('ip-gateway')];
    364       for (var i = 0; i < fields.length; ++i) {
    365         fields[i].editable = !checked;
    366         if (checked) {
    367           var model = fields[i].model;
    368           model.value = model.automatic;
    369           fields[i].model = model;
    370         }
    371       }
    372       if (!checked)
    373         $('ip-address').focus();
    374     },
    375 
    376     /**
    377      * Handler for when the name server selection changes.
    378      * @param {Event} event The click event.
    379      * @private
    380      */
    381     handleNameServerTypeChange_: function(event) {
    382       var type = event.target.value;
    383       DetailsInternetPage.updateNameServerDisplay(type);
    384     },
    385 
    386     /**
    387      * Sends the IP Config info to chrome.
    388      * @param {string} nameServerType The selected name server type:
    389      *   'automatic', 'google', or 'user'.
    390      * @private
    391      */
    392     sendIpConfig_: function(nameServerType) {
    393       var userNameServerString = '';
    394       if (nameServerType == 'user') {
    395         var userNameServers = [];
    396         for (var i = 1; i <= 4; ++i) {
    397           var nameServerField = $('ipconfig-dns' + i);
    398           // Skip empty values.
    399           if (nameServerField && nameServerField.model &&
    400               nameServerField.model.value) {
    401             userNameServers.push(nameServerField.model.value);
    402           }
    403         }
    404         userNameServerString = userNameServers.sort().join(',');
    405       }
    406       chrome.send('setIPConfig',
    407                   [this.servicePath_,
    408                    Boolean($('ip-automatic-configuration-checkbox').checked),
    409                    $('ip-address').model.value || '',
    410                    $('ip-netmask').model.value || '',
    411                    $('ip-gateway').model.value || '',
    412                    nameServerType,
    413                    userNameServerString]);
    414     },
    415 
    416     /**
    417      * Creates an indicator event for controlled properties using
    418      * the same dictionary format as CoreOptionsHandler::CreateValueForPref.
    419      * @param {string} name The name for the Event.
    420      * @param {{value: *, controlledBy: *, recommendedValue: *}} propData
    421      *     Property dictionary.
    422      * @private
    423      */
    424     createControlledEvent_: function(name, propData) {
    425       assert('value' in propData && 'controlledBy' in propData &&
    426              'recommendedValue' in propData);
    427       var event = new Event(name);
    428       event.value = {
    429         value: propData.value,
    430         controlledBy: propData.controlledBy,
    431         recommendedValue: propData.recommendedValue
    432       };
    433       return event;
    434     },
    435 
    436     /**
    437      * Creates an indicator event for controlled properties using
    438      * the ONC getManagedProperties dictionary format.
    439      * @param {string} name The name for the Event.
    440      * @param {Object} propData ONC managed network property dictionary.
    441      * @private
    442      */
    443     createManagedEvent_: function(name, propData) {
    444       var event = new Event(name);
    445       event.value = {};
    446 
    447       // Set the current value and recommended value.
    448       var activeValue = propData['Active'];
    449       var effective = propData['Effective'];
    450       if (activeValue == undefined)
    451         activeValue = propData[effective];
    452       event.value.value = activeValue;
    453 
    454       // If a property is editable then it is not enforced, and 'controlledBy'
    455       // is set to 'recommended' unless effective == {User|Shared}Setting, in
    456       // which case the value was modified from the recommended value.
    457       // Otherwise if 'Effective' is set to 'UserPolicy' or 'DevicePolicy' then
    458       // the set value is mandated by the policy.
    459       if (propData['UserEditable']) {
    460         if (effective == 'UserPolicy')
    461           event.value.controlledBy = 'recommended';
    462         event.value.recommendedValue = propData['UserPolicy'];
    463       } else if (propData['DeviceEditable']) {
    464         if (effective == 'DevicePolicy')
    465           event.value.controlledBy = 'recommended';
    466         event.value.recommendedValue = propData['DevicePolicy'];
    467       } else if (effective == 'UserPolicy' || effective == 'DevicePolicy') {
    468         event.value.controlledBy = 'policy';
    469       }
    470 
    471       return event;
    472     },
    473 
    474     /**
    475      * Update details page controls.
    476      */
    477     updateControls: function() {
    478       // Note: onc may be undefined when called from a pref update before
    479       // initialized in sendNetworkDetails.
    480       var onc = this.onc_;
    481 
    482       // Always show the ipconfig section. TODO(stevenjb): Improve the display
    483       // for unconnected networks. Currently the IP address fields may be
    484       // blank if the network is not connected.
    485       $('ipconfig-section').hidden = false;
    486       $('ipconfig-dns-section').hidden = false;
    487 
    488       // Network type related.
    489       updateHidden('#details-internet-page .cellular-details',
    490                    this.type_ != 'Cellular');
    491       updateHidden('#details-internet-page .wifi-details',
    492                    this.type_ != 'WiFi');
    493       updateHidden('#details-internet-page .wimax-details',
    494                    this.type_ != 'WiMAX');
    495       updateHidden('#details-internet-page .vpn-details', this.type_ != 'VPN');
    496       updateHidden('#details-internet-page .proxy-details', !this.showProxy_);
    497 
    498       // Cellular
    499       if (onc && this.type_ == 'Cellular') {
    500         // Hide gsm/cdma specific elements.
    501         if (onc.getActiveValue('Cellular.Family') == 'GSM')
    502           updateHidden('#details-internet-page .cdma-only', true);
    503         else
    504           updateHidden('#details-internet-page .gsm-only', true);
    505       }
    506 
    507       // Wifi
    508 
    509       // Hide network tab for VPN.
    510       updateHidden('#details-internet-page .network-details',
    511                    this.type_ == 'VPN');
    512 
    513       // Password and shared.
    514       var source = onc ? onc.getSource() : 'None';
    515       var shared = (source == 'Device' || source == 'DevicePolicy');
    516       var security = onc ? onc.getWiFiSecurity() : 'None';
    517       updateHidden('#details-internet-page #password-details',
    518                    this.type_ != 'WiFi' || security == 'None');
    519       updateHidden('#details-internet-page #wifi-shared-network', !shared);
    520       updateHidden('#details-internet-page #prefer-network', source == 'None');
    521 
    522       // WiMAX.
    523       updateHidden('#details-internet-page #wimax-shared-network', !shared);
    524 
    525       // Proxy
    526       this.updateProxyBannerVisibility_();
    527       this.toggleSingleProxy_();
    528       if ($('manual-proxy').checked)
    529         this.enableManualProxy_();
    530       else
    531         this.disableManualProxy_();
    532     },
    533 
    534     /**
    535      * Updates info banner visibility state. This function shows the banner
    536      * if proxy is managed or shared-proxies is off for shared network.
    537      * @private
    538      */
    539     updateProxyBannerVisibility_: function() {
    540       var bannerDiv = $('network-proxy-info-banner');
    541       if (!loadTimeData.data_) {
    542         // TODO(pneubeck): This temporarily prevents an exception below until
    543         // i18n of the proxy dialog on the login page is
    544         // fixed. http://crbug.com/242865
    545         bannerDiv.hidden = true;
    546         return;
    547       }
    548 
    549       // Show banner and determine its message if necessary.
    550       var controlledBy = $('direct-proxy').controlledBy;
    551       if (!controlledBy || controlledBy == '') {
    552         bannerDiv.hidden = true;
    553       } else {
    554         bannerDiv.hidden = false;
    555         // The possible banner texts are loaded in proxy_handler.cc.
    556         var bannerText = 'proxyBanner' + controlledBy.charAt(0).toUpperCase() +
    557                          controlledBy.slice(1);
    558         $('banner-text').textContent = loadTimeData.getString(bannerText);
    559       }
    560     },
    561 
    562     /**
    563      * Handler for when the user clicks on the checkbox to allow a
    564      * single proxy usage.
    565      * @private
    566      */
    567     toggleSingleProxy_: function() {
    568       if ($('proxy-all-protocols').checked) {
    569         $('multi-proxy').hidden = true;
    570         $('single-proxy').hidden = false;
    571       } else {
    572         $('multi-proxy').hidden = false;
    573         $('single-proxy').hidden = true;
    574       }
    575     },
    576 
    577     /**
    578      * Handler for when the user clicks on the checkbox to enter
    579      * auto configuration URL.
    580      * @private
    581      */
    582     handleAutoConfigProxy_: function() {
    583       $('proxy-pac-url').disabled = !$('proxy-use-pac-url').checked;
    584     },
    585 
    586     /**
    587      * Handler for selecting a radio button that will disable the manual
    588      * controls.
    589      * @private
    590      */
    591     disableManualProxy_: function() {
    592       $('ignored-host-list').disabled = true;
    593       $('new-host').disabled = true;
    594       $('remove-host').disabled = true;
    595       $('add-host').disabled = true;
    596       $('proxy-all-protocols').disabled = true;
    597       $('proxy-host-name').disabled = true;
    598       $('proxy-host-port').disabled = true;
    599       $('proxy-host-single-name').disabled = true;
    600       $('proxy-host-single-port').disabled = true;
    601       $('secure-proxy-host-name').disabled = true;
    602       $('secure-proxy-port').disabled = true;
    603       $('ftp-proxy').disabled = true;
    604       $('ftp-proxy-port').disabled = true;
    605       $('socks-host').disabled = true;
    606       $('socks-port').disabled = true;
    607       $('proxy-use-pac-url').disabled = $('auto-proxy').disabled ||
    608                                         !$('auto-proxy').checked;
    609       $('proxy-pac-url').disabled = $('proxy-use-pac-url').disabled ||
    610                                     !$('proxy-use-pac-url').checked;
    611       $('auto-proxy-parms').hidden = !$('auto-proxy').checked;
    612       $('manual-proxy-parms').hidden = !$('manual-proxy').checked;
    613       sendChromeMetricsAction('Options_NetworkManualProxy_Disable');
    614     },
    615 
    616     /**
    617      * Handler for selecting a radio button that will enable the manual
    618      * controls.
    619      * @private
    620      */
    621     enableManualProxy_: function() {
    622       $('ignored-host-list').redraw();
    623       var allDisabled = $('manual-proxy').disabled;
    624       $('ignored-host-list').disabled = allDisabled;
    625       $('new-host').disabled = allDisabled;
    626       $('remove-host').disabled = allDisabled;
    627       $('add-host').disabled = allDisabled;
    628       $('proxy-all-protocols').disabled = allDisabled;
    629       $('proxy-host-name').disabled = allDisabled;
    630       $('proxy-host-port').disabled = allDisabled;
    631       $('proxy-host-single-name').disabled = allDisabled;
    632       $('proxy-host-single-port').disabled = allDisabled;
    633       $('secure-proxy-host-name').disabled = allDisabled;
    634       $('secure-proxy-port').disabled = allDisabled;
    635       $('ftp-proxy').disabled = allDisabled;
    636       $('ftp-proxy-port').disabled = allDisabled;
    637       $('socks-host').disabled = allDisabled;
    638       $('socks-port').disabled = allDisabled;
    639       $('proxy-use-pac-url').disabled = true;
    640       $('proxy-pac-url').disabled = true;
    641       $('auto-proxy-parms').hidden = !$('auto-proxy').checked;
    642       $('manual-proxy-parms').hidden = !$('manual-proxy').checked;
    643       sendChromeMetricsAction('Options_NetworkManualProxy_Enable');
    644     },
    645 
    646     /**
    647      * Helper method called from showDetailedInfo and updateConnectionData.
    648      * Updates visibility/enabled of the login/disconnect/configure buttons.
    649      * @private
    650      */
    651     updateConnectionButtonVisibilty_: function() {
    652       var onc = this.onc_;
    653       if (this.type_ == 'Ethernet') {
    654         // Ethernet can never be connected or disconnected and can always be
    655         // configured (e.g. to set security).
    656         $('details-internet-login').hidden = true;
    657         $('details-internet-disconnect').hidden = true;
    658         $('details-internet-configure').hidden = false;
    659         return;
    660       }
    661 
    662       var connectState = onc.getActiveValue('ConnectionState');
    663       if (connectState == 'NotConnected') {
    664         $('details-internet-login').hidden = false;
    665         // Connecting to an unconfigured network might trigger certificate
    666         // installation UI. Until that gets handled here, always enable the
    667         // Connect button.
    668         $('details-internet-login').disabled = false;
    669         $('details-internet-disconnect').hidden = true;
    670       } else {
    671         $('details-internet-login').hidden = true;
    672         $('details-internet-disconnect').hidden = false;
    673       }
    674 
    675       var connectable = onc.getActiveValue('Connectable');
    676       if (connectState != 'Connected' &&
    677           (!connectable || onc.getWiFiSecurity() != 'None' ||
    678           (this.type_ == 'WiMAX' || this.type_ == 'VPN'))) {
    679         $('details-internet-configure').hidden = false;
    680       } else {
    681         $('details-internet-configure').hidden = true;
    682       }
    683     },
    684 
    685     /**
    686      * Helper method called from showDetailedInfo and updateConnectionData.
    687      * Updates the connection state property and account / sim card links.
    688      * @private
    689      */
    690     updateDetails_: function() {
    691       var onc = this.onc_;
    692 
    693       var connectionStateString = onc.getTranslatedValue('ConnectionState');
    694       $('connection-state').textContent = connectionStateString;
    695 
    696       var type = this.type_;
    697       var showViewAccount = false;
    698       var showActivate = false;
    699       if (type == 'WiFi') {
    700         $('wifi-connection-state').textContent = connectionStateString;
    701       } else if (type == 'WiMAX') {
    702         $('wimax-connection-state').textContent = connectionStateString;
    703       } else if (type == 'Cellular') {
    704         $('activation-state').textContent =
    705             onc.getTranslatedValue('Cellular.ActivationState');
    706         if (onc.getActiveValue('Cellular.Family') == 'GSM') {
    707           var lockEnabled =
    708               onc.getActiveValue('Cellular.SIMLockStatus.LockEnabled');
    709           $('sim-card-lock-enabled').checked = lockEnabled;
    710           $('change-pin').hidden = !lockEnabled;
    711         }
    712         showViewAccount = this.showViewAccountButton_;
    713         var activationState = onc.getActiveValue('Cellular.ActivationState');
    714         showActivate = activationState == 'NotActivated' ||
    715             activationState == 'PartiallyActivated';
    716       }
    717 
    718       $('view-account-details').hidden = !showViewAccount;
    719       $('activate-details').hidden = !showActivate;
    720       // If activation is not complete, hide the login button.
    721       if (showActivate)
    722         $('details-internet-login').hidden = true;
    723     },
    724 
    725     /**
    726      * Helper method called from showDetailedInfo and updateConnectionData.
    727      * Updates the fields in the header section of the details frame.
    728      * @private
    729      */
    730     populateHeader_: function() {
    731       var onc = this.onc_;
    732 
    733       $('network-details-title').textContent = onc.getTranslatedValue('Name');
    734       var connectionState = onc.getActiveValue('ConnectionState');
    735       var connectionStateString = onc.getTranslatedValue('ConnectionState');
    736       $('network-details-subtitle-status').textContent = connectionStateString;
    737 
    738       var typeKey;
    739       var type = this.type_;
    740       if (type == 'Ethernet')
    741         typeKey = 'ethernetTitle';
    742       else if (type == 'WiFi')
    743         typeKey = 'wifiTitle';
    744       else if (type == 'WiMAX')
    745         typeKey = 'wimaxTitle';
    746       else if (type == 'Cellular')
    747         typeKey = 'cellularTitle';
    748       else if (type == 'VPN')
    749         typeKey = 'vpnTitle';
    750       else
    751         typeKey = null;
    752       var typeLabel = $('network-details-subtitle-type');
    753       var typeSeparator = $('network-details-subtitle-separator');
    754       if (typeKey) {
    755         typeLabel.textContent = loadTimeData.getString(typeKey);
    756         typeLabel.hidden = false;
    757         typeSeparator.hidden = false;
    758       } else {
    759         typeLabel.hidden = true;
    760         typeSeparator.hidden = true;
    761       }
    762     },
    763 
    764     /**
    765      * Helper method called from showDetailedInfo to initialize the Apn list.
    766      * @private
    767      */
    768     initializeApnList_: function() {
    769       var onc = this.onc_;
    770 
    771       var apnSelector = $('select-apn');
    772       // Clear APN lists, keep only last element that "other".
    773       while (apnSelector.length != 1) {
    774         apnSelector.remove(0);
    775       }
    776       var otherOption = apnSelector[0];
    777       var activeApn = onc.getActiveValue('Cellular.APN.AccessPointName');
    778       var activeUsername = onc.getActiveValue('Cellular.APN.Username');
    779       var activePassword = onc.getActiveValue('Cellular.APN.Password');
    780       var lastGoodApn =
    781           onc.getActiveValue('Cellular.LastGoodAPN.AccessPointName');
    782       var lastGoodUsername =
    783           onc.getActiveValue('Cellular.LastGoodAPN.Username');
    784       var lastGoodPassword =
    785           onc.getActiveValue('Cellular.LastGoodAPN.Password');
    786       var apnList = onc.getActiveValue('Cellular.APNList');
    787       for (var i = 0; i < apnList.length; i++) {
    788         var apnDict = apnList[i];
    789         var option = document.createElement('option');
    790         var localizedName = apnDict['LocalizedName'];
    791         var name = localizedName ? localizedName : apnDict['Name'];
    792         var accessPointName = apnDict['AccessPointName'];
    793         option.textContent =
    794             name ? (name + ' (' + accessPointName + ')') : accessPointName;
    795         option.value = i;
    796         // Insert new option before "other" option.
    797         apnSelector.add(option, otherOption);
    798         if (this.selectedApnIndex_ != -1)
    799           continue;
    800         // If this matches the active Apn, or LastGoodApn (or there is no last
    801         // good APN), set it as the selected Apn.
    802         if ((activeApn == accessPointName &&
    803              activeUsername == apnDict['Username'] &&
    804              activePassword == apnDict['Password']) ||
    805             (!activeApn && !lastGoodApn) ||
    806             (!activeApn &&
    807              lastGoodApn == accessPointName &&
    808              lastGoodUsername == apnDict['Username'] &&
    809              lastGoodPassword == apnDict['Password'])) {
    810           this.selectedApnIndex_ = i;
    811         }
    812       }
    813       if (this.selectedApnIndex_ == -1 && activeApn) {
    814         var activeOption = document.createElement('option');
    815         activeOption.textContent = activeApn;
    816         activeOption.value = -1;
    817         apnSelector.add(activeOption, otherOption);
    818         this.selectedApnIndex_ = apnSelector.length - 2;
    819         this.userApnIndex_ = this.selectedApnIndex_;
    820       }
    821       assert(this.selectedApnIndex_ >= 0);
    822       apnSelector.selectedIndex = this.selectedApnIndex_;
    823       updateHidden('.apn-list-view', false);
    824       updateHidden('.apn-details-view', true);
    825     },
    826 
    827     /**
    828      * Event Listener for the cellular-apn-use-default button.
    829      * @private
    830      */
    831     setDefaultApn_: function() {
    832       var onc = this.onc_;
    833       var apnSelector = $('select-apn');
    834 
    835       if (this.userApnIndex_ != -1) {
    836         apnSelector.remove(this.userApnIndex_);
    837         this.userApnIndex_ = -1;
    838       }
    839 
    840       var iApn = -1;
    841       var apnList = onc.getActiveValue('Cellular.APNList');
    842       if (apnList != undefined && apnList.length > 0) {
    843         iApn = 0;
    844         var defaultApn = apnList[iApn];
    845         var activeApn = {};
    846         activeApn['AccessPointName'] =
    847             stringFromValue(defaultApn['AccessPointName']);
    848         activeApn['Username'] = stringFromValue(defaultApn['Username']);
    849         activeApn['Password'] = stringFromValue(defaultApn['Password']);
    850         onc.setManagedProperty('Cellular.APN', activeApn);
    851         chrome.send('setApn', [this.servicePath_,
    852                                activeApn['AccessPointName'],
    853                                activeApn['Username'],
    854                                activeApn['Password']]);
    855       }
    856       apnSelector.selectedIndex = iApn;
    857       this.selectedApnIndex_ = iApn;
    858 
    859       updateHidden('.apn-list-view', false);
    860       updateHidden('.apn-details-view', true);
    861     },
    862 
    863     /**
    864      * Event Listener for the cellular-apn-set button.
    865      * @private
    866      */
    867     setApn_: function(apnValue) {
    868       if (apnValue == '')
    869         return;
    870 
    871       var onc = this.onc_;
    872       var apnSelector = $('select-apn');
    873 
    874       var activeApn = {};
    875       activeApn['AccessPointName'] = stringFromValue(apnValue);
    876       activeApn['Username'] = stringFromValue($('cellular-apn-username').value);
    877       activeApn['Password'] = stringFromValue($('cellular-apn-password').value);
    878       onc.setManagedProperty('Cellular.APN', activeApn);
    879       this.userApn_ = activeApn;
    880       chrome.send('setApn', [this.servicePath_,
    881                              activeApn['AccessPointName'],
    882                              activeApn['Username'],
    883                              activeApn['Password']]);
    884 
    885       if (this.userApnIndex_ != -1) {
    886         apnSelector.remove(this.userApnIndex_);
    887         this.userApnIndex_ = -1;
    888       }
    889 
    890       var option = document.createElement('option');
    891       option.textContent = activeApn['AccessPointName'];
    892       option.value = -1;
    893       option.selected = true;
    894       apnSelector.add(option, apnSelector[apnSelector.length - 1]);
    895       this.userApnIndex_ = apnSelector.length - 2;
    896       this.selectedApnIndex_ = this.userApnIndex_;
    897 
    898       updateHidden('.apn-list-view', false);
    899       updateHidden('.apn-details-view', true);
    900     },
    901 
    902     /**
    903      * Event Listener for the cellular-apn-cancel button.
    904      * @private
    905      */
    906     cancelApn_: function() {
    907       $('select-apn').selectedIndex = this.selectedApnIndex_;
    908       updateHidden('.apn-list-view', false);
    909       updateHidden('.apn-details-view', true);
    910     },
    911 
    912     /**
    913      * Event Listener for the select-apn button.
    914      * @private
    915      */
    916     selectApn_: function() {
    917       var onc = this.onc_;
    918       var apnSelector = $('select-apn');
    919       var apnDict;
    920       if (apnSelector[apnSelector.selectedIndex].value != -1) {
    921         var apnList = onc.getActiveValue('Cellular.APNList');
    922         var apnIndex = apnSelector.selectedIndex;
    923         assert(apnIndex < apnList.length);
    924         apnDict = apnList[apnIndex];
    925         chrome.send('setApn', [this.servicePath_,
    926                                stringFromValue(apnDict['AccessPointName']),
    927                                stringFromValue(apnDict['Username']),
    928                                stringFromValue(apnDict['Password'])]);
    929         this.selectedApnIndex_ = apnIndex;
    930       } else if (apnSelector.selectedIndex == this.userApnIndex_) {
    931         apnDict = this.userApn_;
    932         chrome.send('setApn', [this.servicePath_,
    933                                stringFromValue(apnDict['AccessPointName']),
    934                                stringFromValue(apnDict['Username']),
    935                                stringFromValue(apnDict['Password'])]);
    936         this.selectedApnIndex_ = apnSelector.selectedIndex;
    937       } else {
    938         $('cellular-apn').value =
    939             stringFromValue(onc.getActiveValue('Cellular.APN.AccessPointName'));
    940         $('cellular-apn-username').value =
    941             stringFromValue(onc.getActiveValue('Cellular.APN.Username'));
    942         $('cellular-apn-password').value =
    943             stringFromValue(onc.getActiveValue('Cellular.APN.Password'));
    944         updateHidden('.apn-list-view', true);
    945         updateHidden('.apn-details-view', false);
    946       }
    947     }
    948   };
    949 
    950   /**
    951    * Enables or Disables all buttons that provide operations on the cellular
    952    * network.
    953    */
    954   DetailsInternetPage.changeCellularButtonsState = function(disable) {
    955     var buttonsToDisableList =
    956         new Array('details-internet-login',
    957                   'details-internet-disconnect',
    958                   'details-internet-configure',
    959                   'activate-details',
    960                   'view-account-details');
    961 
    962     for (var i = 0; i < buttonsToDisableList.length; ++i) {
    963       var button = $(buttonsToDisableList[i]);
    964       button.disabled = disable;
    965     }
    966   };
    967 
    968   /**
    969    * Shows a spinner while the carrier is changed.
    970    */
    971   DetailsInternetPage.showCarrierChangeSpinner = function(visible) {
    972     $('switch-carrier-spinner').hidden = !visible;
    973     // Disable any buttons that allow us to operate on cellular networks.
    974     DetailsInternetPage.changeCellularButtonsState(visible);
    975   };
    976 
    977   /**
    978    * Changes the network carrier.
    979    */
    980   DetailsInternetPage.handleCarrierChanged = function() {
    981     var carrierSelector = $('select-carrier');
    982     var carrier = carrierSelector[carrierSelector.selectedIndex].textContent;
    983     DetailsInternetPage.showCarrierChangeSpinner(true);
    984     chrome.send('setCarrier', [
    985       DetailsInternetPage.getInstance().servicePath_, carrier]);
    986   };
    987 
    988   /**
    989    * Performs minimal initialization of the InternetDetails dialog in
    990    * preparation for showing proxy-settings.
    991    */
    992   DetailsInternetPage.initializeProxySettings = function() {
    993     DetailsInternetPage.getInstance().initializePageContents_();
    994   };
    995 
    996   /**
    997    * Displays the InternetDetails dialog with only the proxy settings visible.
    998    */
    999   DetailsInternetPage.showProxySettings = function() {
   1000     var detailsPage = DetailsInternetPage.getInstance();
   1001     $('network-details-header').hidden = true;
   1002     $('activate-details').hidden = true;
   1003     $('view-account-details').hidden = true;
   1004     $('web-proxy-auto-discovery').hidden = true;
   1005     detailsPage.showProxy_ = true;
   1006     updateHidden('#internet-tab', true);
   1007     updateHidden('#details-tab-strip', true);
   1008     updateHidden('#details-internet-page .action-area', true);
   1009     detailsPage.updateControls();
   1010     detailsPage.visible = true;
   1011     sendChromeMetricsAction('Options_NetworkShowProxyTab');
   1012   };
   1013 
   1014   /**
   1015    * Initializes even handling for keyboard driven flow.
   1016    */
   1017   DetailsInternetPage.initializeKeyboardFlow = function() {
   1018     keyboard.initializeKeyboardFlow();
   1019   };
   1020 
   1021   DetailsInternetPage.updateProxySettings = function(type) {
   1022       var proxyHost = null,
   1023           proxyPort = null;
   1024 
   1025       if (type == 'cros.session.proxy.singlehttp') {
   1026         proxyHost = 'proxy-host-single-name';
   1027         proxyPort = 'proxy-host-single-port';
   1028       } else if (type == 'cros.session.proxy.httpurl') {
   1029         proxyHost = 'proxy-host-name';
   1030         proxyPort = 'proxy-host-port';
   1031       } else if (type == 'cros.session.proxy.httpsurl') {
   1032         proxyHost = 'secure-proxy-host-name';
   1033         proxyPort = 'secure-proxy-port';
   1034       } else if (type == 'cros.session.proxy.ftpurl') {
   1035         proxyHost = 'ftp-proxy';
   1036         proxyPort = 'ftp-proxy-port';
   1037       } else if (type == 'cros.session.proxy.socks') {
   1038         proxyHost = 'socks-host';
   1039         proxyPort = 'socks-port';
   1040       } else {
   1041         return;
   1042       }
   1043 
   1044       var hostValue = $(proxyHost).value;
   1045       if (hostValue.indexOf(':') !== -1) {
   1046         if (hostValue.match(/:/g).length == 1) {
   1047           hostValue = hostValue.split(':');
   1048           $(proxyHost).value = hostValue[0];
   1049           $(proxyPort).value = hostValue[1];
   1050         }
   1051       }
   1052   };
   1053 
   1054   DetailsInternetPage.updateCarrier = function() {
   1055     DetailsInternetPage.showCarrierChangeSpinner(false);
   1056   };
   1057 
   1058   DetailsInternetPage.loginFromDetails = function() {
   1059     var detailsPage = DetailsInternetPage.getInstance();
   1060     if (detailsPage.type_ == 'WiFi')
   1061       sendChromeMetricsAction('Options_NetworkConnectToWifi');
   1062     else if (detailsPage.type_ == 'VPN')
   1063       sendChromeMetricsAction('Options_NetworkConnectToVPN');
   1064     // TODO(stevenjb): chrome.networkingPrivate.disableNetworkType
   1065     chrome.send('startConnect', [detailsPage.servicePath_]);
   1066     PageManager.closeOverlay();
   1067   };
   1068 
   1069   DetailsInternetPage.disconnectNetwork = function() {
   1070     var detailsPage = DetailsInternetPage.getInstance();
   1071     if (detailsPage.type_ == 'WiFi')
   1072       sendChromeMetricsAction('Options_NetworkDisconnectWifi');
   1073     else if (detailsPage.type_ == 'VPN')
   1074       sendChromeMetricsAction('Options_NetworkDisconnectVPN');
   1075     // TODO(stevenjb): chrome.networkingPrivate.startDisconnect
   1076     chrome.send('startDisconnect', [detailsPage.servicePath_]);
   1077     PageManager.closeOverlay();
   1078   };
   1079 
   1080   DetailsInternetPage.configureNetwork = function() {
   1081     var detailsPage = DetailsInternetPage.getInstance();
   1082     chrome.send('networkCommand',
   1083                 [detailsPage.type_, detailsPage.servicePath_, 'configure']);
   1084     PageManager.closeOverlay();
   1085   };
   1086 
   1087   DetailsInternetPage.activateFromDetails = function() {
   1088     var detailsPage = DetailsInternetPage.getInstance();
   1089     if (detailsPage.type_ == 'Cellular') {
   1090       chrome.send('networkCommand',
   1091                   [detailsPage.type_, detailsPage.servicePath_, 'activate']);
   1092     }
   1093     PageManager.closeOverlay();
   1094   };
   1095 
   1096   /**
   1097    * Event handler called when the details page is closed. Sends changed
   1098    * properties to Chrome and closes the overlay.
   1099    */
   1100   DetailsInternetPage.setDetails = function() {
   1101     var detailsPage = DetailsInternetPage.getInstance();
   1102     var type = detailsPage.type_;
   1103     var servicePath = detailsPage.servicePath_;
   1104     if (type == 'WiFi') {
   1105       sendCheckedIfEnabled(servicePath,
   1106                            'setPreferNetwork',
   1107                            'prefer-network-wifi',
   1108                            'Options_NetworkSetPrefer');
   1109       sendCheckedIfEnabled(servicePath,
   1110                            'setAutoConnect',
   1111                            'auto-connect-network-wifi',
   1112                            'Options_NetworkAutoConnect');
   1113     } else if (type == 'WiMAX') {
   1114       sendCheckedIfEnabled(servicePath,
   1115                            'setAutoConnect',
   1116                            'auto-connect-network-wimax',
   1117                            'Options_NetworkAutoConnect');
   1118     } else if (type == 'Cellular') {
   1119       sendCheckedIfEnabled(servicePath,
   1120                            'setAutoConnect',
   1121                            'auto-connect-network-cellular',
   1122                            'Options_NetworkAutoConnect');
   1123     } else if (type == 'VPN') {
   1124       chrome.send('setServerHostname',
   1125                   [servicePath, $('inet-server-hostname').value]);
   1126       sendCheckedIfEnabled(servicePath,
   1127                            'setAutoConnect',
   1128                            'auto-connect-network-vpn',
   1129                            'Options_NetworkAutoConnect');
   1130     }
   1131 
   1132     var nameServerTypes = ['automatic', 'google', 'user'];
   1133     var nameServerType = 'automatic';
   1134     for (var i = 0; i < nameServerTypes.length; ++i) {
   1135       if ($(nameServerTypes[i] + '-dns-radio').checked) {
   1136         nameServerType = nameServerTypes[i];
   1137         break;
   1138       }
   1139     }
   1140     detailsPage.sendIpConfig_(nameServerType);
   1141 
   1142     PageManager.closeOverlay();
   1143   };
   1144 
   1145   /**
   1146    * Event handler called when the name server type changes.
   1147    * @param {string} type The selected name sever type, 'automatic', 'google',
   1148    *                      or 'user'.
   1149    */
   1150   DetailsInternetPage.updateNameServerDisplay = function(type) {
   1151     var editable = type == 'user';
   1152     var fields = [$('ipconfig-dns1'), $('ipconfig-dns2'),
   1153                   $('ipconfig-dns3'), $('ipconfig-dns4')];
   1154     for (var i = 0; i < fields.length; ++i) {
   1155       fields[i].editable = editable;
   1156     }
   1157     if (editable)
   1158       $('ipconfig-dns1').focus();
   1159 
   1160     var automaticDns = $('automatic-dns-display');
   1161     var googleDns = $('google-dns-display');
   1162     var userDns = $('user-dns-settings');
   1163     switch (type) {
   1164       case 'automatic':
   1165         automaticDns.setAttribute('selected', '');
   1166         googleDns.removeAttribute('selected');
   1167         userDns.removeAttribute('selected');
   1168         break;
   1169       case 'google':
   1170         automaticDns.removeAttribute('selected');
   1171         googleDns.setAttribute('selected', '');
   1172         userDns.removeAttribute('selected');
   1173         break;
   1174       case 'user':
   1175         automaticDns.removeAttribute('selected');
   1176         googleDns.removeAttribute('selected');
   1177         userDns.setAttribute('selected', '');
   1178         break;
   1179     }
   1180   };
   1181 
   1182   /**
   1183    * Method called from Chrome with a dictionary of non ONC configuration
   1184    * properties, including the HUID and service path to be used for requesting
   1185    * the ONC properties. Note: currently GUID is only used to confirm that the
   1186    * selected network still exists. It will be used instead of servicePath
   1187    * once switching to the networkingPrivate API (see TODO below).
   1188    * @param {InternetDetailedInfo} info
   1189    */
   1190   DetailsInternetPage.showDetailedInfo = function(info) {
   1191     if (!('GUID' in info)) {
   1192       // No network was found for, close the overlay.
   1193       PageManager.closeOverlay();
   1194       return;
   1195     }
   1196     var detailsPage = DetailsInternetPage.getInstance();
   1197     detailsPage.servicePath_ = info.servicePath;
   1198     detailsPage.showCarrierSelect_ = info.showCarrierSelect;
   1199     detailsPage.showViewAccountButton_ = info.showViewAccountButton;
   1200     // Ask Chrome to call sendNetworkDetails with the ONC properties.
   1201     // TODO(stevenjb): Use networkingPrivate.getManagedProperties(info.guid).
   1202     chrome.send('getManagedProperties', [info.servicePath]);
   1203   };
   1204 
   1205   /**
   1206    * Method called from Chrome when the ONC properties for the displayed
   1207    * network may have changed.
   1208    * @param {Object} update The updated ONC dictionary for the network.
   1209    */
   1210   DetailsInternetPage.updateConnectionData = function(oncData) {
   1211     var detailsPage = DetailsInternetPage.getInstance();
   1212     if (!detailsPage.visible)
   1213       return;
   1214 
   1215     if (oncData.servicePath != detailsPage.servicePath_)
   1216       return;
   1217 
   1218     // Update our cached data object.
   1219     detailsPage.onc_ = new OncData(oncData);
   1220 
   1221     detailsPage.populateHeader_();
   1222     detailsPage.updateConnectionButtonVisibilty_();
   1223     detailsPage.updateDetails_();
   1224   };
   1225 
   1226   /**
   1227    * Method called from Chrome when the initial dictionary of ONC configuration
   1228    * properties is available.
   1229    * @param {Object} oncData Dictionary of ONC properties.
   1230    */
   1231   DetailsInternetPage.sendNetworkDetails = function(oncData) {
   1232     var onc = new OncData(oncData);
   1233 
   1234     var detailsPage = DetailsInternetPage.getInstance();
   1235     detailsPage.onc_ = onc;
   1236     var type = onc.getActiveValue('Type');
   1237     detailsPage.type_ = type;
   1238 
   1239     sendShowDetailsMetrics(type, onc.getActiveValue('ConnectionState'));
   1240 
   1241     detailsPage.populateHeader_();
   1242     detailsPage.updateConnectionButtonVisibilty_();
   1243     detailsPage.updateDetails_();
   1244 
   1245     // TODO(stevenjb): Some of the setup below should be moved to
   1246     // updateDetails_() so that updates are reflected in the UI.
   1247 
   1248     // Only show proxy for remembered networks.
   1249     var remembered = onc.getSource() != 'None';
   1250     if (remembered) {
   1251       detailsPage.showProxy_ = true;
   1252       // Inform Chrome which network to use for proxy configuration.
   1253       chrome.send('selectNetwork', [detailsPage.servicePath_]);
   1254     } else {
   1255       detailsPage.showProxy_ = false;
   1256     }
   1257 
   1258     $('web-proxy-auto-discovery').hidden = true;
   1259 
   1260     var restricted = onc.getActiveValue('RestrictedConnectivity');
   1261     var restrictedString = loadTimeData.getString(
   1262         restricted ? 'restrictedYes' : 'restrictedNo');
   1263 
   1264     var inetAddress = {};
   1265     var inetNetmask = {};
   1266     var inetGateway = {};
   1267 
   1268     var inetNameServersString;
   1269 
   1270     var ipconfigList = onc.getActiveValue('IPConfigs');
   1271     if (Array.isArray(ipconfigList)) {
   1272       for (var i = 0; i < ipconfigList.length; ++i) {
   1273         var ipconfig = ipconfigList[i];
   1274         var ipType = ipconfig['Type'];
   1275         if (ipType != 'IPv4') {
   1276           // TODO(stevenjb): Handle IPv6 properties.
   1277           continue;
   1278         }
   1279         var address = ipconfig['IPAddress'];
   1280         inetAddress.automatic = address;
   1281         inetAddress.value = address;
   1282         var netmask = prefixLengthToNetmask(ipconfig['RoutingPrefix']);
   1283         inetNetmask.automatic = netmask;
   1284         inetNetmask.value = netmask;
   1285         var gateway = ipconfig['Gateway'];
   1286         inetGateway.automatic = gateway;
   1287         inetGateway.value = gateway;
   1288         if ('WebProxyAutoDiscoveryUrl' in ipconfig) {
   1289           $('web-proxy-auto-discovery').hidden = false;
   1290           $('web-proxy-auto-discovery-url').value =
   1291               ipconfig['WebProxyAutoDiscoveryUrl'];
   1292         }
   1293         if ('NameServers' in ipconfig) {
   1294           var inetNameServers = ipconfig['NameServers'];
   1295           inetNameServers = inetNameServers.sort();
   1296           inetNameServersString = inetNameServers.join(',');
   1297         }
   1298         break;  // Use the first IPv4 entry.
   1299       }
   1300     }
   1301 
   1302     // Override the "automatic" values with the real saved DHCP values,
   1303     // if they are set.
   1304     var savedNameServersString;
   1305     var savedIpAddress = onc.getActiveValue('SavedIPConfig.IPAddress');
   1306     if (savedIpAddress != undefined) {
   1307       inetAddress.automatic = savedIpAddress;
   1308       inetAddress.value = savedIpAddress;
   1309     }
   1310     var savedPrefix = onc.getActiveValue('SavedIPConfig.RoutingPrefix');
   1311     if (savedPrefix != undefined) {
   1312       var savedNetmask = prefixLengthToNetmask(savedPrefix);
   1313       inetNetmask.automatic = savedNetmask;
   1314       inetNetmask.value = savedNetmask;
   1315     }
   1316     var savedGateway = onc.getActiveValue('SavedIPConfig.Gateway');
   1317     if (savedGateway != undefined) {
   1318       inetGateway.automatic = savedGateway;
   1319       inetGateway.value = savedGateway;
   1320     }
   1321     var savedNameServers = onc.getActiveValue('SavedIPConfig.NameServers');
   1322     if (savedNameServers) {
   1323       savedNameServers = savedNameServers.sort();
   1324       savedNameServersString = savedNameServers.join(',');
   1325     }
   1326 
   1327     var ipAutoConfig = 'automatic';
   1328 
   1329     var staticNameServersString;
   1330     var staticIpAddress = onc.getActiveValue('StaticIPConfig.IPAddress');
   1331     if (staticIpAddress != undefined) {
   1332       ipAutoConfig = 'user';
   1333       inetAddress.user = staticIpAddress;
   1334       inetAddress.value = staticIpAddress;
   1335     }
   1336     var staticPrefix = onc.getActiveValue('StaticIPConfig.RoutingPrefix');
   1337     if (staticPrefix != undefined) {
   1338       var staticNetmask = prefixLengthToNetmask(staticPrefix);
   1339       inetNetmask.user = staticNetmask;
   1340       inetNetmask.value = staticNetmask;
   1341     }
   1342     var staticGateway = onc.getActiveValue('StaticIPConfig.Gateway');
   1343     if (staticGateway != undefined) {
   1344       inetGateway.user = staticGateway;
   1345       inetGateway.value = staticGateway;
   1346     }
   1347     var staticNameServers = onc.getActiveValue('StaticIPConfig.NameServers');
   1348     if (staticNameServers) {
   1349       staticNameServers = staticNameServers.sort();
   1350       staticNameServersString = staticNameServers.join(',');
   1351     }
   1352 
   1353     $('ip-automatic-configuration-checkbox').checked =
   1354         ipAutoConfig == 'automatic';
   1355 
   1356     inetAddress.autoConfig = ipAutoConfig;
   1357     inetNetmask.autoConfig = ipAutoConfig;
   1358     inetGateway.autoConfig = ipAutoConfig;
   1359 
   1360     var configureAddressField = function(field, model) {
   1361       IPAddressField.decorate(field);
   1362       field.model = model;
   1363       field.editable = model.autoConfig == 'user';
   1364     };
   1365     configureAddressField($('ip-address'), inetAddress);
   1366     configureAddressField($('ip-netmask'), inetNetmask);
   1367     configureAddressField($('ip-gateway'), inetGateway);
   1368 
   1369     // Set Nameserver fields.
   1370     var nameServerType = 'automatic';
   1371     if (staticNameServersString) {
   1372       // If static nameservers are defined and match the google name servers,
   1373       // show that in the UI, otherwise show the custom static nameservers.
   1374       if (staticNameServersString == GoogleNameServersString)
   1375         nameServerType = 'google';
   1376       else if (staticNameServersString == inetNameServersString)
   1377         nameServerType = 'user';
   1378     }
   1379     if (nameServerType == 'automatic')
   1380       $('automatic-dns-display').textContent = inetNameServersString;
   1381     else
   1382       $('automatic-dns-display').textContent = savedNameServersString;
   1383     $('google-dns-display').textContent = GoogleNameServersString;
   1384 
   1385     var nameServersUser = [];
   1386     if (staticNameServers) {
   1387       nameServersUser = staticNameServers;
   1388     } else if (savedNameServers) {
   1389       // Pre-populate with values provided by DHCP server.
   1390       nameServersUser = savedNameServers;
   1391     }
   1392 
   1393     var nameServerModels = [];
   1394     for (var i = 0; i < 4; ++i)
   1395       nameServerModels.push({value: nameServersUser[i] || ''});
   1396 
   1397     $(nameServerType + '-dns-radio').checked = true;
   1398     configureAddressField($('ipconfig-dns1'), nameServerModels[0]);
   1399     configureAddressField($('ipconfig-dns2'), nameServerModels[1]);
   1400     configureAddressField($('ipconfig-dns3'), nameServerModels[2]);
   1401     configureAddressField($('ipconfig-dns4'), nameServerModels[3]);
   1402 
   1403     DetailsInternetPage.updateNameServerDisplay(nameServerType);
   1404 
   1405     var macAddress = onc.getActiveValue('MacAddress');
   1406     if (macAddress) {
   1407       $('hardware-address').textContent = macAddress;
   1408       $('hardware-address-row').style.display = 'table-row';
   1409     } else {
   1410       // This is most likely a device without a hardware address.
   1411       $('hardware-address-row').style.display = 'none';
   1412     }
   1413 
   1414     var setOrHideParent = function(field, property) {
   1415       if (property != undefined) {
   1416         $(field).textContent = property;
   1417         $(field).parentElement.hidden = false;
   1418       } else {
   1419         $(field).parentElement.hidden = true;
   1420       }
   1421     };
   1422 
   1423     var networkName = onc.getTranslatedValue('Name');
   1424 
   1425     // Signal strength as percentage (for WiFi and WiMAX).
   1426     var signalStrength;
   1427     if (type == 'WiFi' || type == 'WiMAX')
   1428       signalStrength = onc.getActiveValue(type + '.SignalStrength');
   1429     if (!signalStrength)
   1430       signalStrength = 0;
   1431     var strengthFormat = loadTimeData.getString('inetSignalStrengthFormat');
   1432     var strengthString = strengthFormat.replace('$1', signalStrength);
   1433 
   1434     if (type == 'WiFi') {
   1435       OptionsPage.showTab($('wifi-network-nav-tab'));
   1436       $('wifi-restricted-connectivity').textContent = restrictedString;
   1437       var ssid = onc.getActiveValue('WiFi.SSID');
   1438       $('wifi-ssid').textContent = ssid ? ssid : networkName;
   1439       setOrHideParent('wifi-bssid', onc.getActiveValue('WiFi.BSSID'));
   1440       var security = onc.getWiFiSecurity();
   1441       if (security == 'None')
   1442         security = undefined;
   1443       setOrHideParent('wifi-security', security);
   1444       // Frequency is in MHz.
   1445       var frequency = onc.getActiveValue('WiFi.Frequency');
   1446       if (!frequency)
   1447         frequency = 0;
   1448       var frequencyFormat = loadTimeData.getString('inetFrequencyFormat');
   1449       frequencyFormat = frequencyFormat.replace('$1', frequency);
   1450       $('wifi-frequency').textContent = frequencyFormat;
   1451       $('wifi-signal-strength').textContent = strengthString;
   1452       setOrHideParent('wifi-hardware-address',
   1453                       onc.getActiveValue('MacAddress'));
   1454       var priority = onc.getActiveValue('Priority');
   1455       $('prefer-network-wifi').checked = priority > 0;
   1456       $('prefer-network-wifi').disabled = !remembered;
   1457       $('auto-connect-network-wifi').checked =
   1458           onc.getActiveValue('WiFi.AutoConnect');
   1459       $('auto-connect-network-wifi').disabled = !remembered;
   1460     } else if (type == 'WiMAX') {
   1461       OptionsPage.showTab($('wimax-network-nav-tab'));
   1462       $('wimax-restricted-connectivity').textContent = restrictedString;
   1463 
   1464       $('auto-connect-network-wimax').checked =
   1465           onc.getActiveValue('WiMAX.AutoConnect');
   1466       $('auto-connect-network-wimax').disabled = !remembered;
   1467       var identity = onc.getActiveValue('WiMAX.EAP.Identity');
   1468       setOrHideParent('wimax-eap-identity', identity);
   1469       $('wimax-signal-strength').textContent = strengthString;
   1470     } else if (type == 'Cellular') {
   1471       OptionsPage.showTab($('cellular-conn-nav-tab'));
   1472 
   1473       var isGsm = onc.getActiveValue('Cellular.Family') == 'GSM';
   1474 
   1475       var currentCarrierIndex = -1;
   1476       if (this.showCarrierSelect_) {
   1477         var currentCarrier =
   1478             isGsm ? CarrierGenericUMTS : onc.getActiveValue('Cellular.Carrier');
   1479         var supportedCarriers =
   1480             onc.getActiveValue('Cellular.SupportedCarriers');
   1481         for (var c1 = 0; c1 < supportedCarriers.length; ++c1) {
   1482           if (supportedCarriers[c1] == currentCarrier) {
   1483             currentCarrierIndex = c1;
   1484             break;
   1485           }
   1486         }
   1487         if (currentCarrierIndex != -1) {
   1488           var carrierSelector = $('select-carrier');
   1489           carrierSelector.onchange = DetailsInternetPage.handleCarrierChanged;
   1490           carrierSelector.options.length = 0;
   1491           for (var c2 = 0; c2 < supportedCarriers.length; ++c2) {
   1492             var option = document.createElement('option');
   1493             option.textContent = supportedCarriers[c2];
   1494             carrierSelector.add(option);
   1495           }
   1496           carrierSelector.selectedIndex = currentCarrierIndex;
   1497         }
   1498       }
   1499       if (currentCarrierIndex == -1)
   1500         $('service-name').textContent = networkName;
   1501 
   1502       $('network-technology').textContent =
   1503           onc.getActiveValue('Cellular.NetworkTechnology');
   1504       $('roaming-state').textContent =
   1505           onc.getTranslatedValue('Cellular.RoamingState');
   1506       $('cellular-restricted-connectivity').textContent = restrictedString;
   1507       // 'errorMessage' is a non ONC property added by Chrome.
   1508       $('error-state').textContent = onc.getActiveValue('errorMessage');
   1509       $('manufacturer').textContent =
   1510           onc.getActiveValue('Cellular.Manufacturer');
   1511       $('model-id').textContent = onc.getActiveValue('Cellular.ModelID');
   1512       $('firmware-revision').textContent =
   1513           onc.getActiveValue('Cellular.FirmwareRevision');
   1514       $('hardware-revision').textContent =
   1515           onc.getActiveValue('Cellular.HardwareRevision');
   1516       $('mdn').textContent = onc.getActiveValue('Cellular.MDN');
   1517 
   1518       // Show ServingOperator properties only if available.
   1519       var servingOperatorName =
   1520           onc.getActiveValue('Cellular.ServingOperator.Name');
   1521       var servingOperatorCode =
   1522           onc.getActiveValue('Cellular.ServingOperator.Code');
   1523       if (servingOperatorName != undefined &&
   1524           servingOperatorCode != undefined) {
   1525         $('operator-name').textContent = servingOperatorName;
   1526         $('operator-code').textContent = servingOperatorCode;
   1527       } else {
   1528         $('operator-name').parentElement.hidden = true;
   1529         $('operator-code').parentElement.hidden = true;
   1530       }
   1531       // Make sure that GSM/CDMA specific properties that shouldn't be hidden
   1532       // are visible.
   1533       updateHidden('#details-internet-page .gsm-only', false);
   1534       updateHidden('#details-internet-page .cdma-only', false);
   1535 
   1536       // Show IMEI/ESN/MEID/MIN/PRL only if they are available.
   1537       setOrHideParent('esn', onc.getActiveValue('Cellular.ESN'));
   1538       setOrHideParent('imei', onc.getActiveValue('Cellular.IMEI'));
   1539       setOrHideParent('meid', onc.getActiveValue('Cellular.MEID'));
   1540       setOrHideParent('min', onc.getActiveValue('Cellular.MIN'));
   1541       setOrHideParent('prl-version', onc.getActiveValue('Cellular.PRLVersion'));
   1542 
   1543       if (isGsm) {
   1544         $('iccid').textContent = onc.getActiveValue('Cellular.ICCID');
   1545         $('imsi').textContent = onc.getActiveValue('Cellular.IMSI');
   1546         detailsPage.initializeApnList_();
   1547       }
   1548       $('auto-connect-network-cellular').checked =
   1549           onc.getActiveValue('Cellular.AutoConnect');
   1550       $('auto-connect-network-cellular').disabled = false;
   1551     } else if (type == 'VPN') {
   1552       OptionsPage.showTab($('vpn-nav-tab'));
   1553       $('inet-service-name').textContent = networkName;
   1554       $('inet-provider-type').textContent =
   1555           onc.getTranslatedValue('VPN.Type');
   1556       var providerType = onc.getActiveValue('VPN.Type');
   1557       var usernameKey;
   1558       if (providerType == 'OpenVPN')
   1559         usernameKey = 'VPN.OpenVPN.Username';
   1560       else if (providerType == 'L2TP-IPsec')
   1561         usernameKey = 'VPN.L2TP.Username';
   1562 
   1563       if (usernameKey) {
   1564         $('inet-username').parentElement.hidden = false;
   1565         $('inet-username').textContent = onc.getActiveValue(usernameKey);
   1566       } else {
   1567         $('inet-username').parentElement.hidden = true;
   1568       }
   1569       var inetServerHostname = $('inet-server-hostname');
   1570       inetServerHostname.value = onc.getActiveValue('VPN.Host');
   1571       inetServerHostname.resetHandler = function() {
   1572         PageManager.hideBubble();
   1573         var recommended = onc.getRecommendedValue('VPN.Host');
   1574         if (recommended != undefined)
   1575           inetServerHostname.value = recommended;
   1576       };
   1577       $('auto-connect-network-vpn').checked =
   1578           onc.getActiveValue('VPN.AutoConnect');
   1579       $('auto-connect-network-vpn').disabled = false;
   1580     } else {
   1581       OptionsPage.showTab($('internet-nav-tab'));
   1582     }
   1583 
   1584     // Update controlled option indicators.
   1585     var indicators = cr.doc.querySelectorAll(
   1586         '#details-internet-page .controlled-setting-indicator');
   1587     for (var i = 0; i < indicators.length; i++) {
   1588       var managed = indicators[i].hasAttribute('managed');
   1589       // TODO(stevenjb): Eliminate support for 'data' once 39 is stable.
   1590       var attributeName = managed ? 'managed' : 'data';
   1591       var propName = indicators[i].getAttribute(attributeName);
   1592       if (!propName)
   1593         continue;
   1594       var propValue = managed ?
   1595           onc.getManagedProperty(propName) :
   1596           onc.getActiveValue(propName);
   1597       // If the property is unset or unmanaged (i.e. not an Object) skip it.
   1598       if (propValue == undefined || (typeof propValue != 'object'))
   1599         continue;
   1600       var event;
   1601       if (managed)
   1602         event = detailsPage.createManagedEvent_(propName, propValue);
   1603       else
   1604         event = detailsPage.createControlledEvent_(propName,
   1605             /** @type {{value: *, controlledBy: *, recommendedValue: *}} */(
   1606                 propValue));
   1607       indicators[i].handlePrefChange(event);
   1608       var forElement = $(indicators[i].getAttribute('for'));
   1609       if (forElement) {
   1610         if (event.value.controlledBy == 'policy')
   1611           forElement.disabled = true;
   1612         if (forElement.resetHandler)
   1613           indicators[i].resetHandler = forElement.resetHandler;
   1614       }
   1615     }
   1616 
   1617     detailsPage.updateControls();
   1618 
   1619     // Don't show page name in address bar and in history to prevent people
   1620     // navigate here by hand and solve issue with page session restore.
   1621     PageManager.showPageByName('detailsInternetPage', false);
   1622   };
   1623 
   1624   return {
   1625     DetailsInternetPage: DetailsInternetPage
   1626   };
   1627 });
   1628