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